[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant] branch master updated: Factor out 13 new functions (shi
From: |
gnunet |
Subject: |
[taler-merchant] branch master updated: Factor out 13 new functions (shit job) |
Date: |
Sat, 13 May 2023 07:17:43 +0200 |
This is an automated email from the git hooks/post-receive script.
ivan-avalos pushed a commit to branch master
in repository merchant.
The following commit(s) were added to refs/heads/master by this push:
new 594aa457 Factor out 13 new functions (shit job)
594aa457 is described below
commit 594aa4576f9ec45315c4d253356b9962d59d46c2
Author: Iván Ávalos <avalos@disroot.org>
AuthorDate: Fri May 12 23:16:21 2023 -0600
Factor out 13 new functions (shit job)
---
src/backenddb/Makefile.am | 13 +
src/backenddb/pg_delete_contract_terms.c | 59 +
src/backenddb/pg_delete_contract_terms.h | 47 +
src/backenddb/pg_delete_order.c | 87 +
src/backenddb/pg_delete_order.h | 45 +
src/backenddb/pg_expire_locks.c | 84 +
src/backenddb/pg_expire_locks.h | 38 +
src/backenddb/pg_insert_contract_terms.c | 132 +
src/backenddb/pg_insert_contract_terms.h | 52 +
src/backenddb/pg_insert_order.c | 82 +
src/backenddb/pg_insert_order.h | 53 +
src/backenddb/pg_insert_order_lock.c | 78 +
src/backenddb/pg_insert_order_lock.h | 47 +
src/backenddb/pg_lookup_contract_terms.c | 82 +
src/backenddb/pg_lookup_contract_terms.h | 50 +
src/backenddb/pg_lookup_contract_terms2.c | 96 +
src/backenddb/pg_lookup_contract_terms2.h | 54 +
src/backenddb/pg_lookup_order.c | 96 +
src/backenddb/pg_lookup_order.h | 49 +
src/backenddb/pg_lookup_order_summary.c | 75 +
src/backenddb/pg_lookup_order_summary.h | 45 +
src/backenddb/pg_lookup_orders.c | 926 +++++
src/backenddb/pg_lookup_orders.h | 45 +
src/backenddb/pg_unlock_inventory.c | 47 +
src/backenddb/pg_unlock_inventory.h | 42 +
src/backenddb/pg_update_contract_terms.c | 103 +
src/backenddb/pg_update_contract_terms.h | 49 +
src/backenddb/plugin_merchantdb_postgres.c | 5833 ++++++++++------------------
28 files changed, 4623 insertions(+), 3786 deletions(-)
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 91b48223..1b400bce 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -81,6 +81,19 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
pg_insert_product.h pg_insert_product.c \
pg_update_product.h pg_update_product.c \
pg_lock_product.h pg_lock_product.c \
+ pg_expire_locks.h pg_expire_locks.c \
+ pg_delete_order.h pg_delete_order.c \
+ pg_lookup_order.h pg_lookup_order.c \
+ pg_lookup_order_summary.h pg_lookup_order_summary.c \
+ pg_lookup_orders.h pg_lookup_orders.c \
+ pg_insert_order.h pg_insert_order.c \
+ pg_unlock_inventory.h pg_unlock_inventory.c \
+ pg_insert_order_lock.h pg_insert_order_lock.c \
+ pg_lookup_contract_terms2.h pg_lookup_contract_terms2.c \
+ pg_lookup_contract_terms.h pg_lookup_contract_terms.c \
+ pg_insert_contract_terms.h pg_insert_contract_terms.c \
+ pg_update_contract_terms.h pg_update_contract_terms.c \
+ pg_delete_contract_terms.h pg_delete_contract_terms.c \
plugin_merchantdb_postgres.c pg_helper.h
libtaler_plugin_merchantdb_postgres_la_LIBADD = \
$(LTLIBINTL)
diff --git a/src/backenddb/pg_delete_contract_terms.c
b/src/backenddb/pg_delete_contract_terms.c
new file mode 100644
index 00000000..708a724a
--- /dev/null
+++ b/src/backenddb/pg_delete_contract_terms.c
@@ -0,0 +1,59 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_contract_terms.c
+ * @brief Implementation of the delete_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_contract_terms (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct GNUNET_TIME_Relative legal_expiration)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_relative_time (&legal_expiration),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "delete_contract_terms",
+ "DELETE FROM merchant_contract_terms"
+ " WHERE order_id=$2"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND ( ( (pay_deadline < $4) AND"
+ " (NOT paid) ) OR"
+ " (creation_time + $3 < $4) )");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_contract_terms",
+ params);
+}
diff --git a/src/backenddb/pg_delete_contract_terms.h
b/src/backenddb/pg_delete_contract_terms.h
new file mode 100644
index 00000000..ce74a3c5
--- /dev/null
+++ b/src/backenddb/pg_delete_contract_terms.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_contract_terms.h
+ * @brief implementation of the delete_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_DELETE_CONTRACT_TERMS_H
+#define PG_DELETE_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Delete information about a contract. Note that the transaction must
+ * enforce that the contract is not awaiting payment anymore AND was not
+ * paid, or is past the legal expiration.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete order of
+ * @param order_id order to delete
+ * @param legal_expiration how long do we need to keep (paid) contracts on
+ * file for legal reasons (i.e. taxation)
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if locks prevent deletion OR order unknown
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_contract_terms (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct GNUNET_TIME_Relative legal_expiration);
+
+#endif
diff --git a/src/backenddb/pg_delete_order.c b/src/backenddb/pg_delete_order.c
new file mode 100644
index 00000000..e058be3b
--- /dev/null
+++ b/src/backenddb/pg_delete_order.c
@@ -0,0 +1,87 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_order.c
+ * @brief Implementation of the delete_order function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_order.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_order (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ bool force)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_bool (force),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_QueryParam params2[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "delete_order",
+ "WITH ms AS"
+ "(SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ ", mc AS"
+ "(SELECT paid"
+ " FROM merchant_contract_terms"
+ " JOIN ms USING (merchant_serial)"
+ " WHERE order_id=$2) "
+ "DELETE"
+ " FROM merchant_orders mo"
+ " WHERE order_id=$2"
+ " AND merchant_serial=(SELECT merchant_serial FROM ms)"
+ " AND ( (pay_deadline < $3)"
+ " OR (NOT EXISTS (SELECT paid FROM mc))"
+ " OR ($4 AND (FALSE=(SELECT paid FROM mc))) );");
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_order",
+ params);
+ if ( (qs <= 0) || (! force))
+ return qs;
+ PREPARE (pg,
+ "delete_contract",
+ "DELETE"
+ " FROM merchant_contract_terms"
+ " WHERE order_id=$2 AND"
+ " merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND NOT paid;");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_contract",
+ params2);
+}
diff --git a/src/backenddb/pg_delete_order.h b/src/backenddb/pg_delete_order.h
new file mode 100644
index 00000000..58f3e5bb
--- /dev/null
+++ b/src/backenddb/pg_delete_order.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_order.h
+ * @brief implementation of the delete_order function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_DELETE_ORDER_H
+#define PG_DELETE_ORDER_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Delete information about an order. Note that the transaction must
+ * enforce that the order is not awaiting payment anymore.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete order of
+ * @param order_id order to delete
+ * @param force delete claimed but unpaid orders as well
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if pending payment prevents deletion OR order unknown
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_order (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ bool force);
+
+#endif
diff --git a/src/backenddb/pg_expire_locks.c b/src/backenddb/pg_expire_locks.c
new file mode 100644
index 00000000..4b12ba04
--- /dev/null
+++ b/src/backenddb/pg_expire_locks.c
@@ -0,0 +1,84 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_expire_locks.c
+ * @brief Implementation of the expire_locks function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_expire_locks.h"
+#include "pg_helper.h"
+
+void
+TMH_PG_expire_locks (void *cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs1;
+ enum GNUNET_DB_QueryStatus qs2;
+ enum GNUNET_DB_QueryStatus qs3;
+
+ check_connection (pg);
+ PREPARE (pg,
+ "unlock_products",
+ "DELETE FROM merchant_inventory_locks"
+ " WHERE expiration < $1");
+ qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "unlock_products",
+ params);
+ if (qs1 < 0)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ PREPARE (pg,
+ "unlock_orders",
+ "DELETE FROM merchant_orders"
+ " WHERE pay_deadline < $1");
+ qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "unlock_orders",
+ params);
+ if (qs2 < 0)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ PREPARE (pg,
+ "unlock_contracts",
+ "DELETE FROM merchant_contract_terms"
+ " WHERE NOT paid"
+ " AND pay_deadline < $1");
+ qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "unlock_contracts",
+ params);
+ if (qs3 < 0)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Released %d+%d+%d locks\n",
+ qs1,
+ qs2,
+ qs3);
+}
diff --git a/src/backenddb/pg_expire_locks.h b/src/backenddb/pg_expire_locks.h
new file mode 100644
index 00000000..6eac73de
--- /dev/null
+++ b/src/backenddb/pg_expire_locks.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_expire_locks.h
+ * @brief implementation of the expire_locks function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_EXPIRE_LOCKS_H
+#define PG_EXPIRE_LOCKS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Release all expired product locks, including
+ * those from expired offers -- across all
+ * instances.
+ *
+ * @param cls closure
+ */
+void
+TMH_PG_expire_locks (void *cls);
+
+#endif
diff --git a/src/backenddb/pg_insert_contract_terms.c
b/src/backenddb/pg_insert_contract_terms.c
new file mode 100644
index 00000000..2bc6ab86
--- /dev/null
+++ b/src/backenddb/pg_insert_contract_terms.c
@@ -0,0 +1,132 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_contract_terms.c
+ * @brief Implementation of the insert_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_contract_terms (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t *contract_terms,
+ uint64_t *order_serial)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Timestamp pay_deadline;
+ struct GNUNET_TIME_Timestamp refund_deadline;
+ const char *fulfillment_url;
+ struct TALER_PrivateContractHashP h_contract_terms;
+
+ if (GNUNET_OK !=
+ TALER_JSON_contract_hash (contract_terms,
+ &h_contract_terms))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_timestamp ("pay_deadline",
+ &pay_deadline),
+ GNUNET_JSON_spec_timestamp ("refund_deadline",
+ &refund_deadline),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (NULL,
+ contract_terms,
+ spec);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ }
+
+ fulfillment_url =
+ json_string_value (json_object_get (contract_terms,
+ "fulfillment_url"));
+ check_connection (pg);
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ TALER_PQ_query_param_json (contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
+ GNUNET_PQ_query_param_timestamp (&pay_deadline),
+ GNUNET_PQ_query_param_timestamp (&refund_deadline),
+ (NULL == fulfillment_url)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (fulfillment_url),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ order_serial),
+ GNUNET_PQ_result_spec_end
+ };
+ PREPARE (pg,
+ "insert_contract_terms",
+ "INSERT INTO merchant_contract_terms"
+ "(order_serial"
+ ",merchant_serial"
+ ",order_id"
+ ",contract_terms"
+ ",h_contract_terms"
+ ",creation_time"
+ ",pay_deadline"
+ ",refund_deadline"
+ ",fulfillment_url"
+ ",claim_token"
+ ",pos_key"
+ ",pos_algorithm)"
+ "SELECT"
+ " mo.order_serial"
+ ",mo.merchant_serial"
+ ",mo.order_id"
+ ",$3" /* contract_terms */
+ ",$4" /* h_contract_terms */
+ ",mo.creation_time"
+ ",$5" /* pay_deadline */
+ ",$6" /* refund_deadline */
+ ",$7" /* fulfillment_url */
+ ",mo.claim_token"
+ ",mo.pos_key"
+ ",mo.pos_algorithm"
+ " FROM merchant_orders mo"
+ " WHERE order_id=$2"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " RETURNING order_serial");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "insert_contract_terms",
+ params,
+ rs);
+ }
+}
diff --git a/src/backenddb/pg_insert_contract_terms.h
b/src/backenddb/pg_insert_contract_terms.h
new file mode 100644
index 00000000..8f22f5b8
--- /dev/null
+++ b/src/backenddb/pg_insert_contract_terms.h
@@ -0,0 +1,52 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_contract_terms.h
+ * @brief implementation of the insert_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_INSERT_CONTRACT_TERMS_H
+#define PG_INSERT_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Store contract terms given its @a order_id. Note that some attributes are
+ * expected to be calculated inside of the function, like the hash of the
+ * contract terms (to be hashed), the creation_time and pay_deadline (to be
+ * obtained from the merchant_orders table). The "session_id" should be
+ * initially set to the empty string. The "fulfillment_url" and
"refund_deadline"
+ * must be extracted from @a contract_terms.
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to store
+ * @param contract_terms contract terms to store
+ * @param[out] order_serial set to the serial of the order
+ * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a
contract_terms
+ * is malformed
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_contract_terms (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t *contract_terms,
+ uint64_t *order_serial);
+
+#endif
diff --git a/src/backenddb/pg_insert_order.c b/src/backenddb/pg_insert_order.c
new file mode 100644
index 00000000..7c7ad486
--- /dev/null
+++ b/src/backenddb/pg_insert_order.c
@@ -0,0 +1,82 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order.c
+ * @brief Implementation of the insert_order function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_order.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const struct TALER_MerchantPostDataHashP *h_post_data,
+ struct GNUNET_TIME_Timestamp pay_deadline,
+ const struct TALER_ClaimTokenP *claim_token,
+ const json_t *contract_terms,
+ const char *pos_key,
+ enum TALER_MerchantConfirmationAlgorithm pos_algorithm)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Timestamp now;
+ uint32_t pos32 = (uint32_t) pos_algorithm;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_timestamp (&pay_deadline),
+ GNUNET_PQ_query_param_auto_from_type (claim_token),
+ GNUNET_PQ_query_param_auto_from_type (h_post_data),
+ GNUNET_PQ_query_param_timestamp (&now),
+ TALER_PQ_query_param_json (contract_terms),
+ (NULL == pos_key)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (pos_key),
+ GNUNET_PQ_query_param_uint32 (&pos32),
+ GNUNET_PQ_query_param_end
+ };
+
+ now = GNUNET_TIME_timestamp_get ();
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "inserting order: order_id: %s, instance_id: %s.\n",
+ order_id,
+ instance_id);
+ check_connection (pg);
+ PREPARE (pg,
+ "insert_order",
+ "INSERT INTO merchant_orders"
+ "(merchant_serial"
+ ",order_id"
+ ",pay_deadline"
+ ",claim_token"
+ ",h_post_data"
+ ",creation_time"
+ ",contract_terms"
+ ",pos_key"
+ ",pos_algorithm)"
+ " SELECT merchant_serial,"
+ " $2, $3, $4, $5, $6, $7, $8, $9"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_order",
+ params);
+}
diff --git a/src/backenddb/pg_insert_order.h b/src/backenddb/pg_insert_order.h
new file mode 100644
index 00000000..297d9bdf
--- /dev/null
+++ b/src/backenddb/pg_insert_order.h
@@ -0,0 +1,53 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order.h
+ * @brief implementation of the insert_order function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_INSERT_ORDER_H
+#define PG_INSERT_ORDER_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Insert order into the DB.
+ *
+ * @param cls closure
+ * @param instance_id identifies the instance responsible for the order
+ * @param order_id alphanumeric string that uniquely identifies the proposal
+ * @param h_post_data hash of the POST data for idempotency checks
+ * @param pay_deadline how long does the customer have to pay for the order
+ * @param claim_token token to use for access control
+ * @param contract_terms proposal data to store
+ * @param pos_key encoded key for payment verification
+ * @param pos_algorithm algorithm to compute the payment verification
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const struct TALER_MerchantPostDataHashP *h_post_data,
+ struct GNUNET_TIME_Timestamp pay_deadline,
+ const struct TALER_ClaimTokenP *claim_token,
+ const json_t *contract_terms,
+ const char *pos_key,
+ enum TALER_MerchantConfirmationAlgorithm pos_algorithm);
+
+#endif
diff --git a/src/backenddb/pg_insert_order_lock.c
b/src/backenddb/pg_insert_order_lock.c
new file mode 100644
index 00000000..862a6320
--- /dev/null
+++ b/src/backenddb/pg_insert_order_lock.c
@@ -0,0 +1,78 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order_lock.c
+ * @brief Implementation of the insert_order_lock function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_order_lock.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order_lock (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const char *product_id,
+ uint64_t quantity)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_string (product_id),
+ GNUNET_PQ_query_param_uint64 (&quantity),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "insert_order_lock",
+ "WITH tmp AS"
+ " (SELECT "
+ " product_serial"
+ " ,merchant_serial"
+ " ,total_stock"
+ " ,total_sold"
+ " ,total_lost"
+ " FROM merchant_inventory"
+ " WHERE product_id=$3"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1))"
+ " INSERT INTO merchant_order_locks"
+ " (product_serial"
+ " ,total_locked"
+ " ,order_serial)"
+ " SELECT tmp.product_serial, $4, order_serial"
+ " FROM merchant_orders"
+ " JOIN tmp USING(merchant_serial)"
+ " WHERE order_id=$2 AND"
+ " tmp.total_stock - tmp.total_sold - tmp.total_lost - $4 >= "
+ " (SELECT COALESCE(SUM(total_locked), 0)"
+ " FROM merchant_inventory_locks"
+ " WHERE product_serial=tmp.product_serial) + "
+ " (SELECT COALESCE(SUM(total_locked), 0)"
+ " FROM merchant_order_locks"
+ " WHERE product_serial=tmp.product_serial)");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_order_lock",
+ params);
+}
diff --git a/src/backenddb/pg_insert_order_lock.h
b/src/backenddb/pg_insert_order_lock.h
new file mode 100644
index 00000000..c2cc9908
--- /dev/null
+++ b/src/backenddb/pg_insert_order_lock.h
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order_lock.h
+ * @brief implementation of the insert_order_lock function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_INSERT_ORDER_LOCK_H
+#define PG_INSERT_ORDER_LOCK_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Lock inventory stock to a particular order.
+ *
+ * @param cls closure
+ * @param instance_id identifies the instance responsible for the order
+ * @param order_id alphanumeric string that uniquely identifies the order
+ * @param product_id uniquely identifies the product to be locked
+ * @param quantity how many units should be locked to the @a order_id
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order_lock (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ const char *product_id,
+ uint64_t quantity);
+
+#endif
diff --git a/src/backenddb/pg_lookup_contract_terms.c
b/src/backenddb/pg_lookup_contract_terms.c
new file mode 100644
index 00000000..e1f24ac4
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms.c
@@ -0,0 +1,82 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms.c
+ * @brief Implementation of the lookup_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t **contract_terms,
+ uint64_t *order_serial,
+ bool *paid,
+ struct TALER_ClaimTokenP *claim_token)
+{
+ struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_ClaimTokenP ct;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ /* contract_terms must be first! */
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ order_serial),
+ GNUNET_PQ_result_spec_bool ("paid",
+ paid),
+ GNUNET_PQ_result_spec_auto_from_type ("claim_token",
+ &ct),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_contract_terms",
+ "SELECT"
+ " contract_terms"
+ ",order_serial"
+ ",claim_token"
+ ",paid"
+ " FROM merchant_contract_terms"
+ " WHERE order_id=$2"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_contract_terms",
+ params,
+ (NULL != contract_terms)
+ ? rs
+ : &rs[1]);
+ if (NULL != claim_token)
+ *claim_token = ct;
+ return qs;
+}
diff --git a/src/backenddb/pg_lookup_contract_terms.h
b/src/backenddb/pg_lookup_contract_terms.h
new file mode 100644
index 00000000..2ab1bb16
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms.h
@@ -0,0 +1,50 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms.h
+ * @brief implementation of the lookup_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_CONTRACT_TERMS_H
+#define PG_LOOKUP_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve contract terms given its @a order_id
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to lookup.
+ * @param[out] contract_terms where to store the result, NULL to only check
for existence
+ * @param[out] order_serial set to the order's serial number
+ * @param[out] paid set to true if the order is fully paid
+ * @param[out] claim_token set to token to use for access control
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t **contract_terms,
+ uint64_t *order_serial,
+ bool *paid,
+ struct TALER_ClaimTokenP *claim_token);
+
+#endif
diff --git a/src/backenddb/pg_lookup_contract_terms2.c
b/src/backenddb/pg_lookup_contract_terms2.c
new file mode 100644
index 00000000..1fbb02ea
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms2.c
@@ -0,0 +1,96 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms2.c
+ * @brief Implementation of the lookup_contract_terms2 function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_contract_terms2.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms2 (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t **contract_terms,
+ uint64_t *order_serial,
+ bool *paid,
+ struct TALER_ClaimTokenP *claim_token,
+ char **pos_key,
+ enum TALER_MerchantConfirmationAlgorithm *pos_algorithm)
+{
+ struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_ClaimTokenP ct;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_end
+ };
+ uint32_t pos32;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ /* contract_terms must be first! */
+ TALER_PQ_result_spec_json ("contract_terms",
+ contract_terms),
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ order_serial),
+ GNUNET_PQ_result_spec_bool ("paid",
+ paid),
+ GNUNET_PQ_result_spec_auto_from_type ("claim_token",
+ &ct),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("pos_key",
+ pos_key),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("pos_algorithm",
+ &pos32),
+ NULL),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_contract_terms2",
+ "SELECT"
+ " contract_terms"
+ ",order_serial"
+ ",claim_token"
+ ",paid"
+ ",pos_key"
+ ",pos_algorithm"
+ " FROM merchant_contract_terms"
+ " WHERE order_id=$2"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_contract_terms2",
+ params,
+ (NULL != contract_terms)
+ ? rs
+ : &rs[1]);
+ *pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32;
+ if (NULL != claim_token)
+ *claim_token = ct;
+ return qs;
+}
diff --git a/src/backenddb/pg_lookup_contract_terms2.h
b/src/backenddb/pg_lookup_contract_terms2.h
new file mode 100644
index 00000000..6c1c8514
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms2.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms2.h
+ * @brief implementation of the lookup_contract_terms2 function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_CONTRACT_TERMS2_H
+#define PG_LOOKUP_CONTRACT_TERMS2_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve contract terms given its @a order_id
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to lookup.
+ * @param[out] contract_terms where to store the result, NULL to only check
for existence
+ * @param[out] order_serial set to the order's serial number
+ * @param[out] paid set to true if the order is fully paid
+ * @param[out] claim_token set to the claim token, NULL to only check for
existence
+ * @param[out] pos_key encoded key for payment verification
+ * @param[out] pos_algorithm algorithm to compute the payment verification
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms2 (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t **contract_terms,
+ uint64_t *order_serial,
+ bool *paid,
+ struct TALER_ClaimTokenP *claim_token,
+ char **pos_key,
+ enum TALER_MerchantConfirmationAlgorithm *pos_algorithm);
+
+#endif
diff --git a/src/backenddb/pg_lookup_order.c b/src/backenddb/pg_lookup_order.c
new file mode 100644
index 00000000..6df7456c
--- /dev/null
+++ b/src/backenddb/pg_lookup_order.c
@@ -0,0 +1,96 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order.c
+ * @brief Implementation of the lookup_order function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_order.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct TALER_ClaimTokenP *claim_token,
+ struct TALER_MerchantPostDataHashP *h_post_data,
+ json_t **contract_terms)
+{
+ struct PostgresClosure *pg = cls;
+ json_t *j;
+ struct TALER_ClaimTokenP ct;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_json ("contract_terms",
+ &j),
+ GNUNET_PQ_result_spec_auto_from_type ("claim_token",
+ &ct),
+ GNUNET_PQ_result_spec_auto_from_type ("h_post_data",
+ h_post_data),
+ GNUNET_PQ_result_spec_end
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Finding contract term, order_id: '%s', instance_id: '%s'.\n",
+ order_id,
+ instance_id);
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_order",
+ "SELECT"
+ " contract_terms"
+ ",claim_token"
+ ",h_post_data"
+ ",pos_key"
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND merchant_orders.order_id=$2");
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_order",
+ params,
+ rs);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ if (NULL != contract_terms)
+ *contract_terms = j;
+ else
+ json_decref (j);
+ if (NULL != claim_token)
+ *claim_token = ct;
+ }
+ else
+ {
+ /* just to be safe: NULL it */
+ if (NULL != contract_terms)
+ *contract_terms = NULL;
+ if (NULL != claim_token)
+ *claim_token = (struct TALER_ClaimTokenP) { 0 }
+ ;
+ }
+ return qs;
+}
diff --git a/src/backenddb/pg_lookup_order.h b/src/backenddb/pg_lookup_order.h
new file mode 100644
index 00000000..7ca60869
--- /dev/null
+++ b/src/backenddb/pg_lookup_order.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order.h
+ * @brief implementation of the lookup_order function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_ORDER_H
+#define PG_LOOKUP_ORDER_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve order given its @a order_id and the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param order_id order id used to perform the lookup
+ * @param[out] claim_token the claim token generated for the order,
+ * NULL to only test if the order exists
+ * @param[out] h_post_data set to the hash of the POST data that created the
order
+ * @param[out] contract_terms where to store the retrieved contract terms,
+ * NULL to only test if the order exists
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct TALER_ClaimTokenP *claim_token,
+ struct TALER_MerchantPostDataHashP *h_post_data,
+ json_t **contract_terms);
+
+#endif
diff --git a/src/backenddb/pg_lookup_order_summary.c
b/src/backenddb/pg_lookup_order_summary.c
new file mode 100644
index 00000000..3a2a4e16
--- /dev/null
+++ b/src/backenddb/pg_lookup_order_summary.c
@@ -0,0 +1,75 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order_summary.c
+ * @brief Implementation of the lookup_order_summary function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_order_summary.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order_summary (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct GNUNET_TIME_Timestamp *timestamp,
+ uint64_t *order_serial)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ order_serial),
+ GNUNET_PQ_result_spec_timestamp ("creation_time",
+ timestamp),
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "lookup_order_summary",
+ "(SELECT"
+ " creation_time"
+ ",order_serial"
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND merchant_contract_terms.order_id=$2)"
+ "UNION"
+ "(SELECT"
+ " creation_time"
+ ",order_serial"
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND merchant_orders.order_id=$2)");
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_order_summary",
+ params,
+ rs);
+}
diff --git a/src/backenddb/pg_lookup_order_summary.h
b/src/backenddb/pg_lookup_order_summary.h
new file mode 100644
index 00000000..5827aa66
--- /dev/null
+++ b/src/backenddb/pg_lookup_order_summary.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order_summary.h
+ * @brief implementation of the lookup_order_summary function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_ORDER_SUMMARY_H
+#define PG_LOOKUP_ORDER_SUMMARY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve order summary given its @a order_id and the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param order_id order id used to perform the lookup
+ * @param[out] timestamp when was the order created
+ * @param[out] order_serial under which serial do we keep this order
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order_summary (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct GNUNET_TIME_Timestamp *timestamp,
+ uint64_t *order_serial);
+
+#endif
diff --git a/src/backenddb/pg_lookup_orders.c b/src/backenddb/pg_lookup_orders.c
new file mode 100644
index 00000000..437ca8ca
--- /dev/null
+++ b/src/backenddb/pg_lookup_orders.c
@@ -0,0 +1,926 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_orders.c
+ * @brief Implementation of the lookup_orders function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_orders.h"
+#include "pg_helper.h"
+
+/**
+ * Context used for TMH_PG_lookup_orders().
+ */
+struct LookupOrdersContext
+{
+ /**
+ * Function to call with the results.
+ */
+ TALER_MERCHANTDB_OrdersCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Did database result extraction fail?
+ */
+ bool extract_failed;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about orders.
+ *
+ * @param[in,out] cls of type `struct LookupOrdersContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lookup_orders_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupOrdersContext *plc = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *order_id;
+ uint64_t order_serial;
+ struct GNUNET_TIME_Timestamp ts;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("order_id",
+ &order_id),
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ &order_serial),
+ GNUNET_PQ_result_spec_timestamp ("creation_time",
+ &ts),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ plc->extract_failed = true;
+ return;
+ }
+ plc->cb (plc->cb_cls,
+ order_id,
+ order_serial,
+ ts);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_orders (void *cls,
+ const char *instance_id,
+ const struct TALER_MERCHANTDB_OrderFilter *of,
+ TALER_MERCHANTDB_OrdersCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct LookupOrdersContext plc = {
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
+ uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
+ uint8_t paid;
+ uint8_t refunded;
+ uint8_t wired;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_uint64 (&limit),
+ GNUNET_PQ_query_param_uint64 (&of->start_row),
+ GNUNET_PQ_query_param_timestamp (&of->date),
+ GNUNET_PQ_query_param_auto_from_type (&paid),
+ GNUNET_PQ_query_param_auto_from_type (&refunded),
+ GNUNET_PQ_query_param_auto_from_type (&wired),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+ char stmt[128];
+
+ paid = (TALER_EXCHANGE_YNA_YES == of->paid);
+ refunded = (TALER_EXCHANGE_YNA_YES == of->refunded);
+ wired = (TALER_EXCHANGE_YNA_YES == of->wired);
+ /* painfully many cases..., note that "_xxx" being present in 'stmt' merely
+ means that we filter by that variable, the value we filter for is
+ computed above */
+ GNUNET_snprintf (stmt,
+ sizeof (stmt),
+ "lookup_orders_%s%s%s%s",
+ (of->delta > 0) ? "inc" : "dec",
+ (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid",
+ (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" :
+ "_refunded",
+ (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired");
+ PREPARE (pg,
+ "lookup_orders_inc",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_paid",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " BOOL($5) = paid"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_refunded",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " CAST($6 as BOOL) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_paid_refunded",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " BOOL($5) = paid"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_paid_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " BOOL($5) = paid"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_refunded_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_inc_paid_refunded_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial > $3"
+ " AND"
+ " creation_time > $4"
+ " AND"
+ " BOOL($5) = paid"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2)"
+ " ORDER BY order_serial ASC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_paid",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($5) = paid"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_refunded",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_paid_refunded",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($5) = paid"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_paid_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($5) = paid"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_refunded_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+ " FROM merchant_refunds))"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ PREPARE (pg,
+ "lookup_orders_dec_paid_refunded_wired",
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ " FROM merchant_orders"
+ " WHERE merchant_orders.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+ " AND"
+ " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+ " AND"
+ " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+ " AND"
+ " order_serial NOT IN"
+ " (SELECT order_serial"
+ " FROM merchant_contract_terms)" /* only select unclaimed
orders */
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ "UNION " /* union ensures elements are distinct! */
+ "(SELECT"
+ " order_id"
+ ",order_serial"
+ ",creation_time"
+ " FROM merchant_contract_terms"
+ " WHERE merchant_contract_terms.merchant_serial="
+ " (SELECT merchant_serial "
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)"
+ " AND"
+ " order_serial < $3"
+ " AND"
+ " creation_time < $4"
+ " AND"
+ " BOOL($5) = paid"
+ " AND"
+ " BOOL($6) = (order_serial IN"
+ " (SELECT order_serial "
+
+ " FROM merchant_refunds))"
+ " AND"
+ " BOOL($7) = wired"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2)"
+ " ORDER BY order_serial DESC"
+ " LIMIT $2");
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ stmt,
+ params,
+ &lookup_orders_cb,
+ &plc);
+ if (plc.extract_failed)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/backenddb/pg_lookup_orders.h b/src/backenddb/pg_lookup_orders.h
new file mode 100644
index 00000000..4b00f18b
--- /dev/null
+++ b/src/backenddb/pg_lookup_orders.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_orders.h
+ * @brief implementation of the lookup_orders function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_ORDERS_H
+#define PG_LOOKUP_ORDERS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve orders given the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param of filter to apply when looking up orders
+ * @param cb callback to pass all the orders that are found
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_orders (void *cls,
+ const char *instance_id,
+ const struct TALER_MERCHANTDB_OrderFilter *of,
+ TALER_MERCHANTDB_OrdersCallback cb,
+ void *cb_cls);
+
+#endif
diff --git a/src/backenddb/pg_unlock_inventory.c
b/src/backenddb/pg_unlock_inventory.c
new file mode 100644
index 00000000..5f4d8a7b
--- /dev/null
+++ b/src/backenddb/pg_unlock_inventory.c
@@ -0,0 +1,47 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_unlock_inventory.c
+ * @brief Implementation of the unlock_inventory function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_unlock_inventory.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_unlock_inventory (void *cls,
+ const struct GNUNET_Uuid *uuid)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (uuid),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ PREPARE (pg,
+ "unlock_inventory",
+ "DELETE"
+ " FROM merchant_inventory_locks"
+ " WHERE lock_uuid=$1");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "unlock_inventory",
+ params);
+}
diff --git a/src/backenddb/pg_unlock_inventory.h
b/src/backenddb/pg_unlock_inventory.h
new file mode 100644
index 00000000..cec734e8
--- /dev/null
+++ b/src/backenddb/pg_unlock_inventory.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_unlock_inventory.h
+ * @brief implementation of the unlock_inventory function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_UNLOCK_INVENTORY_H
+#define PG_UNLOCK_INVENTORY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Release an inventory lock by UUID. Releases ALL stocks locked under
+ * the given UUID.
+ *
+ * @param cls closure
+ * @param uuid the UUID to release locks for
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a
uuid
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_unlock_inventory (void *cls,
+ const struct GNUNET_Uuid *uuid);
+
+#endif
diff --git a/src/backenddb/pg_update_contract_terms.c
b/src/backenddb/pg_update_contract_terms.c
new file mode 100644
index 00000000..51e449a0
--- /dev/null
+++ b/src/backenddb/pg_update_contract_terms.c
@@ -0,0 +1,103 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_contract_terms.c
+ * @brief Implementation of the update_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_contract_terms (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t *contract_terms)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_TIME_Timestamp pay_deadline;
+ struct GNUNET_TIME_Timestamp refund_deadline;
+ const char *fulfillment_url = NULL;
+ struct TALER_PrivateContractHashP h_contract_terms;
+
+ if (GNUNET_OK !=
+ TALER_JSON_contract_hash (contract_terms,
+ &h_contract_terms))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_timestamp ("pay_deadline",
+ &pay_deadline),
+ GNUNET_JSON_spec_timestamp ("refund_deadline",
+ &refund_deadline),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("fulfillment_url",
+ &fulfillment_url),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (NULL,
+ contract_terms,
+ spec);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ }
+
+ check_connection (pg);
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ TALER_PQ_query_param_json (contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
+ GNUNET_PQ_query_param_timestamp (&pay_deadline),
+ GNUNET_PQ_query_param_timestamp (&refund_deadline),
+ (NULL == fulfillment_url)
+ ? GNUNET_PQ_query_param_null ()
+ : GNUNET_PQ_query_param_string (fulfillment_url),
+ GNUNET_PQ_query_param_end
+ };
+ PREPARE (pg,
+ "update_contract_terms",
+ "UPDATE merchant_contract_terms SET"
+ " contract_terms=$3"
+ ",h_contract_terms=$4"
+ ",pay_deadline=$5"
+ ",refund_deadline=$6"
+ ",fulfillment_url=$7"
+ " WHERE order_id=$2"
+ " AND merchant_serial="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)");
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_contract_terms",
+ params);
+ }
+}
diff --git a/src/backenddb/pg_update_contract_terms.h
b/src/backenddb/pg_update_contract_terms.h
new file mode 100644
index 00000000..fe428dc0
--- /dev/null
+++ b/src/backenddb/pg_update_contract_terms.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_contract_terms.h
+ * @brief implementation of the update_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_UPDATE_CONTRACT_TERMS_H
+#define PG_UPDATE_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Update the contract terms stored for @a order_id. Note that some attributes
are
+ * expected to be calculated inside of the function, like the hash of the
+ * contract terms (to be hashed), the creation_time and pay_deadline (to be
+ * obtained from the merchant_orders table). The "session_id" should be
+ * initially set to the empty string. The "fulfillment_url" and
"refund_deadline"
+ * must be extracted from @a contract_terms.
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to store
+ * @param contract_terms contract to store
+ * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a
contract_terms
+ * is malformed
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_contract_terms (void *cls,
+ const char *instance_id,
+ const char *order_id,
+ json_t *contract_terms);
+
+#endif
diff --git a/src/backenddb/plugin_merchantdb_postgres.c
b/src/backenddb/plugin_merchantdb_postgres.c
index 0e5f921f..757a303c 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -59,6 +59,19 @@
#include "pg_insert_product.h"
#include "pg_update_product.h"
#include "pg_lock_product.h"
+#include "pg_expire_locks.h"
+#include "pg_delete_order.h"
+#include "pg_lookup_order.h"
+#include "pg_lookup_order_summary.h"
+#include "pg_lookup_orders.h"
+#include "pg_insert_order.h"
+#include "pg_unlock_inventory.h"
+#include "pg_insert_order_lock.h"
+#include "pg_lookup_contract_terms2.h"
+#include "pg_lookup_contract_terms.h"
+#include "pg_insert_contract_terms.h"
+#include "pg_update_contract_terms.h"
+#include "pg_delete_contract_terms.h"
#include "pg_set_transfer_status_to_confirmed.h"
@@ -337,262 +350,69 @@ postgres_commit (void *cls)
/**
- * Release all expired product locks, including
- * those from expired offers -- across all
- * instances.
- *
- * @param cls closure
- */
-static void
-postgres_expire_locks (void *cls)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs1;
- enum GNUNET_DB_QueryStatus qs2;
- enum GNUNET_DB_QueryStatus qs3;
-
- check_connection (pg);
- qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_products",
- params);
- if (qs1 < 0)
- {
- GNUNET_break (0);
- return;
- }
- qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_orders",
- params);
- if (qs2 < 0)
- {
- GNUNET_break (0);
- return;
- }
- qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_contracts",
- params);
- if (qs3 < 0)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Released %d+%d+%d locks\n",
- qs1,
- qs2,
- qs3);
-}
-
-
-/**
- * Delete information about an order. Note that the transaction must
- * enforce that the order is not awaiting payment anymore.
- *
- * @param cls closure
- * @param instance_id instance to delete order of
- * @param order_id order to delete
- * @param force delete claimed but unpaid orders as well
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if pending payment prevents deletion OR order unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_order (void *cls,
- const char *instance_id,
- const char *order_id,
- bool force)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_absolute_time (&now),
- GNUNET_PQ_query_param_bool (force),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_QueryParam params2[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_order",
- params);
- if ( (qs <= 0) || (! force))
- return qs;
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_contract",
- params2);
-}
-
-
-/**
- * Retrieve order given its @a order_id and the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param order_id order id used to perform the lookup
- * @param[out] claim_token the claim token generated for the order,
- * NULL to only test if the order exists
- * @param[out] h_post_data set to the hash of the POST data that created the
order
- * @param[out] contract_terms where to store the retrieved contract terms,
- * NULL to only test if the order exists
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order (void *cls,
- const char *instance_id,
- const char *order_id,
- struct TALER_ClaimTokenP *claim_token,
- struct TALER_MerchantPostDataHashP *h_post_data,
- json_t **contract_terms)
-{
- struct PostgresClosure *pg = cls;
- json_t *j;
- struct TALER_ClaimTokenP ct;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_result_spec_json ("contract_terms",
- &j),
- GNUNET_PQ_result_spec_auto_from_type ("claim_token",
- &ct),
- GNUNET_PQ_result_spec_auto_from_type ("h_post_data",
- h_post_data),
- GNUNET_PQ_result_spec_end
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Finding contract term, order_id: '%s', instance_id: '%s'.\n",
- order_id,
- instance_id);
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- if (NULL != contract_terms)
- *contract_terms = j;
- else
- json_decref (j);
- if (NULL != claim_token)
- *claim_token = ct;
- }
- else
- {
- /* just to be safe: NULL it */
- if (NULL != contract_terms)
- *contract_terms = NULL;
- if (NULL != claim_token)
- *claim_token = (struct TALER_ClaimTokenP) { 0 }
- ;
- }
- return qs;
-}
-
-
-/**
- * Retrieve order summary given its @a order_id and the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param order_id order id used to perform the lookup
- * @param[out] timestamp when was the order created
- * @param[out] order_serial under which serial do we keep this order
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_summary (void *cls,
- const char *instance_id,
- const char *order_id,
- struct GNUNET_TIME_Timestamp *timestamp,
- uint64_t *order_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_timestamp ("creation_time",
- timestamp),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order_summary",
- params,
- rs);
-}
-
-
-/**
- * Context used for postgres_lookup_orders().
+ * Closure for #lookup_deposits_cb().
*/
-struct LookupOrdersContext
+struct LookupDepositsContext
{
/**
- * Function to call with the results.
+ * Function to call with results.
*/
- TALER_MERCHANTDB_OrdersCallback cb;
+ TALER_MERCHANTDB_DepositsCallback cb;
/**
- * Closure for @a cb.
+ * Closure for @e cls.
*/
void *cb_cls;
/**
- * Did database result extraction fail?
+ * Plugin context.
*/
- bool extract_failed;
+ 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 about orders.
+ * that has returned @a num_results results.
*
- * @param[in,out] cls of type `struct LookupOrdersContext *`
+ * @param[in,out] cls of type `struct LookupDepositsContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_orders_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+lookup_deposits_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct LookupOrdersContext *plc = cls;
+ struct LookupDepositsContext *ldc = cls;
+ struct PostgresClosure *pg = ldc->pg;
- for (unsigned int i = 0; i < num_results; i++)
+ for (unsigned int i = 0; i<num_results; i++)
{
- char *order_id;
- uint64_t order_serial;
- struct GNUNET_TIME_Timestamp ts;
+ 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;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("order_id",
- &order_id),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- &order_serial),
- GNUNET_PQ_result_spec_timestamp ("creation_time",
- &ts),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ 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_end
};
@@ -602,553 +422,583 @@ lookup_orders_cb (void *cls,
i))
{
GNUNET_break (0);
- plc->extract_failed = true;
+ ldc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- plc->cb (plc->cb_cls,
- order_id,
- order_serial,
- ts);
+ ldc->cb (ldc->cb_cls,
+ exchange_url,
+ &coin_pub,
+ &amount_with_fee,
+ &deposit_fee,
+ &refund_fee,
+ &wire_fee);
GNUNET_PQ_cleanup_result (rs);
}
+ ldc->qs = num_results;
}
/**
- * Retrieve orders given the @a instance_id.
+ * Lookup information about coins that were successfully deposited for a
+ * given contract.
*
* @param cls closure
- * @param instance_id instance to obtain order of
- * @param of filter to apply when looking up orders
- * @param cb callback to pass all the orders that are found
+ * @param instance_id instance to lookup deposits for
+ * @param h_contract_terms proposal data's hashcode
+ * @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_orders (void *cls,
- const char *instance_id,
- const struct TALER_MERCHANTDB_OrderFilter *of,
- TALER_MERCHANTDB_OrdersCallback cb,
- void *cb_cls)
+postgres_lookup_deposits (
+ void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ TALER_MERCHANTDB_DepositsCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
- struct LookupOrdersContext plc = {
- .cb = cb,
- .cb_cls = cb_cls
- };
- uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
- uint8_t paid;
- uint8_t refunded;
- uint8_t wired;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&limit),
- GNUNET_PQ_query_param_uint64 (&of->start_row),
- GNUNET_PQ_query_param_timestamp (&of->date),
- GNUNET_PQ_query_param_auto_from_type (&paid),
- GNUNET_PQ_query_param_auto_from_type (&refunded),
- GNUNET_PQ_query_param_auto_from_type (&wired),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_end
};
+ struct LookupDepositsContext ldc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
+ };
enum GNUNET_DB_QueryStatus qs;
- char stmt[128];
- paid = (TALER_EXCHANGE_YNA_YES == of->paid);
- refunded = (TALER_EXCHANGE_YNA_YES == of->refunded);
- wired = (TALER_EXCHANGE_YNA_YES == of->wired);
- /* painfully many cases..., note that "_xxx" being present in 'stmt' merely
- means that we filter by that variable, the value we filter for is
- computed above */
- GNUNET_snprintf (stmt,
- sizeof (stmt),
- "lookup_orders_%s%s%s%s",
- (of->delta > 0) ? "inc" : "dec",
- (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid",
- (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" :
- "_refunded",
- (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired");
+ /* no preflight check here, run in its own transaction by the caller! */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Finding deposits for h_contract_terms '%s'\n",
+ GNUNET_h2s (&h_contract_terms->hash));
+ check_connection (pg);
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- stmt,
+ "lookup_deposits",
params,
- &lookup_orders_cb,
- &plc);
- if (plc.extract_failed)
- return GNUNET_DB_STATUS_HARD_ERROR;
- return qs;
+ &lookup_deposits_cb,
+ &ldc);
+ if (qs <= 0)
+ return qs;
+ return ldc.qs;
}
/**
- * Insert order into the DB.
+ * Insert an exchange signing key into our database.
*
* @param cls closure
- * @param instance_id identifies the instance responsible for the order
- * @param order_id alphanumeric string that uniquely identifies the proposal
- * @param h_post_data hash of the POST data for idempotency checks
- * @param pay_deadline how long does the customer have to pay for the order
- * @param claim_token token to use for access control
- * @param contract_terms proposal data to store
- * @param pos_key encoded key for payment verification
- * @param pos_algorithm algorithm to compute the payment verification
- * @return transaction status
+ * @param master_pub exchange master public key used for @a master_sig
+ * @param exchange_pub exchange signing key to insert
+ * @param start_date when does the signing key become valid
+ * @param expire_date when does the signing key stop being used
+ * @param end_date when does the signing key become void as proof
+ * @param master_sig signature of @a master_pub over the @a exchange_pub and
the dates
*/
static enum GNUNET_DB_QueryStatus
-postgres_insert_order (void *cls,
- const char *instance_id,
- const char *order_id,
- const struct TALER_MerchantPostDataHashP *h_post_data,
- struct GNUNET_TIME_Timestamp pay_deadline,
- const struct TALER_ClaimTokenP *claim_token,
- const json_t *contract_terms,
- const char *pos_key,
- enum TALER_MerchantConfirmationAlgorithm pos_algorithm)
+postgres_insert_exchange_signkey (
+ void *cls,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp expire_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_MasterSignatureP *master_sig)
{
struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp now;
- uint32_t pos32 = (uint32_t) pos_algorithm;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_timestamp (&pay_deadline),
- GNUNET_PQ_query_param_auto_from_type (claim_token),
- GNUNET_PQ_query_param_auto_from_type (h_post_data),
- GNUNET_PQ_query_param_timestamp (&now),
- TALER_PQ_query_param_json (contract_terms),
- (NULL == pos_key)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (pos_key),
- GNUNET_PQ_query_param_uint32 (&pos32),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+ GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+ GNUNET_PQ_query_param_timestamp (&start_date),
+ GNUNET_PQ_query_param_timestamp (&expire_date),
+ GNUNET_PQ_query_param_timestamp (&end_date),
+ GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_end
};
- now = GNUNET_TIME_timestamp_get ();
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "inserting order: order_id: %s, instance_id: %s.\n",
- order_id,
- instance_id);
check_connection (pg);
+ postgres_preflight (pg);
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_order",
+ "insert_exchange_signkey",
params);
+
}
/**
- * Release an inventory lock by UUID. Releases ALL stocks locked under
- * the given UUID.
+ * Insert payment confirmation from the exchange into the database.
*
* @param cls closure
- * @param uuid the UUID to release locks for
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a
uuid
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_unlock_inventory (void *cls,
- const struct GNUNET_Uuid *uuid)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (uuid),
- GNUNET_PQ_query_param_end
+ * @param instance_id instance to lookup deposits for
+ * @param deposit_timestamp time when the exchange generated the deposit
confirmation
+ * @param h_contract_terms proposal data's hashcode
+ * @param coin_pub public key of the coin
+ * @param exchange_url URL of the exchange that issued @a coin_pub
+ * @param amount_with_fee amount the exchange will deposit for this coin
+ * @param deposit_fee fee the exchange will charge for this coin
+ * @param wire_fee wire fee the exchange charges
+ * @param refund_fee fee the exchange charges to refund this coin
+ * @param h_wire hash of the wire details of the target account of the merchant
+ * @param exchange_sig signature from exchange that coin was accepted
+ * @param exchange_pub signgin key that was used for @a exchange_sig
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_deposit (
+ void *cls,
+ const char *instance_id,
+ struct GNUNET_TIME_Timestamp deposit_timestamp,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *exchange_url,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ const struct TALER_Amount *refund_fee,
+ const struct TALER_Amount *wire_fee,
+ const struct TALER_MerchantWireHashP *h_wire,
+ const struct TALER_ExchangeSignatureP *exchange_sig,
+ const struct TALER_ExchangePublicKeyP *exchange_pub)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_timestamp (&deposit_timestamp), /* $3 */
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_string (exchange_url),
+ TALER_PQ_query_param_amount (amount_with_fee), /* $6/$7 */
+ TALER_PQ_query_param_amount (deposit_fee), /* $8, $9 */
+ TALER_PQ_query_param_amount (refund_fee), /* $10, $11 */
+ TALER_PQ_query_param_amount (wire_fee), /* $12, $13 */
+ GNUNET_PQ_query_param_auto_from_type (h_wire), /* $14 */
+ GNUNET_PQ_query_param_auto_from_type (exchange_sig), /* $15 */
+ GNUNET_PQ_query_param_auto_from_type (exchange_pub), /* $16 */
+ GNUNET_PQ_query_param_end
};
+ /* no preflight check here, run in transaction by caller! */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Storing deposit for instance `%s' h_contract_terms `%s',
coin_pub: `%s', amount_with_fee: %s\n",
+ instance_id,
+ GNUNET_h2s (&h_contract_terms->hash),
+ TALER_B2S (coin_pub),
+ TALER_amount2s (amount_with_fee));
check_connection (pg);
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "unlock_inventory",
+ "insert_deposit",
params);
+
}
/**
- * Lock inventory stock to a particular order.
+ * Closure for #lookup_refunds_cb().
+ */
+struct LookupRefundsContext
+{
+ /**
+ * Function to call for each refund.
+ */
+ TALER_MERCHANTDB_RefundCallback rc;
+
+ /**
+ * Closure for @e rc.
+ */
+ void *rc_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Transaction result.
+ */
+ 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 closure
- * @param instance_id identifies the instance responsible for the order
- * @param order_id alphanumeric string that uniquely identifies the order
- * @param product_id uniquely identifies the product to be locked
- * @param quantity how many units should be locked to the @a order_id
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
+ * @param cls of type `struct LookupRefundsContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
*/
-static enum GNUNET_DB_QueryStatus
-postgres_insert_order_lock (void *cls,
- const char *instance_id,
- const char *order_id,
- const char *product_id,
- uint64_t quantity)
+static void
+lookup_refunds_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_string (product_id),
- GNUNET_PQ_query_param_uint64 (&quantity),
- GNUNET_PQ_query_param_end
- };
+ struct LookupRefundsContext *lrc = cls;
+ struct PostgresClosure *pg = lrc->pg;
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_order_lock",
- params);
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_Amount refund_amount;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &coin_pub),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+ &refund_amount),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ lrc->rc (lrc->rc_cls,
+ &coin_pub,
+ &refund_amount);
+ GNUNET_PQ_cleanup_result (rs); /* technically useless here */
+ }
+ lrc->qs = num_results;
}
/**
- * Retrieve contract terms given its @a order_id
+ * Obtain refunds associated with a contract.
*
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to lookup.
- * @param[out] contract_terms where to store the result, NULL to only check
for existence
- * @param[out] order_serial set to the order's serial number
- * @param[out] paid set to true if the order is fully paid
- * @param[out] claim_token set to the claim token, NULL to only check for
existence
- * @param[out] pos_key encoded key for payment verification
- * @param[out] pos_algorithm algorithm to compute the payment verification
+ * @param cls closure, typically a connection to the db
+ * @param instance_id instance to lookup refunds for
+ * @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
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_contract_terms2 (
+postgres_lookup_refunds (
void *cls,
const char *instance_id,
- const char *order_id,
- json_t **contract_terms,
- uint64_t *order_serial,
- bool *paid,
- struct TALER_ClaimTokenP *claim_token,
- char **pos_key,
- enum TALER_MerchantConfirmationAlgorithm *pos_algorithm)
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ TALER_MERCHANTDB_RefundCallback rc,
+ void *rc_cls)
{
struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_ClaimTokenP ct;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_end
};
- uint32_t pos32;
- struct GNUNET_PQ_ResultSpec rs[] = {
- /* contract_terms must be first! */
- TALER_PQ_result_spec_json ("contract_terms",
- contract_terms),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_bool ("paid",
- paid),
- GNUNET_PQ_result_spec_auto_from_type ("claim_token",
- &ct),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_string ("pos_key",
- pos_key),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_uint32 ("pos_algorithm",
- &pos32),
- NULL),
- GNUNET_PQ_result_spec_end
+ struct LookupRefundsContext lrc = {
+ .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 of h_contract_terms %s at `%s'\n",
+ GNUNET_h2s (&h_contract_terms->hash),
+ instance_id);
check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_contract_terms2",
- params,
- (NULL != contract_terms)
- ? rs
- : &rs[1]);
- *pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32;
- if (NULL != claim_token)
- *claim_token = ct;
- return qs;
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_refunds",
+ params,
+ &lookup_refunds_cb,
+ &lrc);
+ if (0 >= qs)
+ return qs;
+ return lrc.qs;
}
/**
- * Retrieve contract terms given its @a order_id
+ * Mark contract as paid and store the current @a session_id
+ * for which the contract was paid. Deletes the underlying order
+ * and marks the locked stocks of the order as sold.
*
* @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to lookup.
- * @param[out] contract_terms where to store the result, NULL to only check
for existence
- * @param[out] order_serial set to the order's serial number
- * @param[out] paid set to true if the order is fully paid
- * @param[out] claim_token set to token to use for access control
+ * @param instance_id instance to mark contract as paid for
+ * @param h_contract_terms hash of the contract that is now paid
+ * @param session_id the session that paid the contract
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_contract_terms (
+postgres_mark_contract_paid (
void *cls,
const char *instance_id,
- const char *order_id,
- json_t **contract_terms,
- uint64_t *order_serial,
- bool *paid,
- struct TALER_ClaimTokenP *claim_token)
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ const char *session_id)
{
struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- struct TALER_ClaimTokenP ct;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_string (session_id),
GNUNET_PQ_query_param_end
};
- struct GNUNET_PQ_ResultSpec rs[] = {
- /* contract_terms must be first! */
- TALER_PQ_result_spec_json ("contract_terms",
- contract_terms),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_bool ("paid",
- paid),
- GNUNET_PQ_result_spec_auto_from_type ("claim_token",
- &ct),
- GNUNET_PQ_result_spec_end
+ struct GNUNET_PQ_QueryParam uparams[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_end
};
+ enum GNUNET_DB_QueryStatus qs;
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_contract_terms",
- params,
- (NULL != contract_terms)
- ? rs
- : &rs[1]);
- if (NULL != claim_token)
- *claim_token = ct;
- return qs;
+ /* Session ID must always be given by the caller. */
+ GNUNET_assert (NULL != session_id);
+
+ /* no preflight check here, run in transaction by caller! */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Marking h_contract_terms '%s' of %s as paid for session `%s'\n",
+ GNUNET_h2s (&h_contract_terms->hash),
+ instance_id,
+ session_id);
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "mark_contract_paid",
+ params);
+ if (qs <= 0)
+ return qs;
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "mark_inventory_sold",
+ uparams);
+ if (qs < 0)
+ return qs; /* 0: no inventory management, that's OK! */
+ /* ON DELETE CASCADE deletes from merchant_order_locks */
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_completed_order",
+ uparams);
}
/**
- * Store contract terms given its @a order_id. Note that some attributes are
- * expected to be calculated inside of the function, like the hash of the
- * contract terms (to be hashed), the creation_time and pay_deadline (to be
- * obtained from the merchant_orders table). The "session_id" should be
- * initially set to the empty string. The "fulfillment_url" and
"refund_deadline"
- * must be extracted from @a contract_terms.
+ * Function called during aborts to refund a coin. Marks the
+ * respective coin as refunded.
*
* @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to store
- * @param contract_terms contract terms to store
- * @param[out] order_serial set to the serial of the order
- * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a
contract_terms
- * is malformed
+ * @param instance_id instance to refund payment for
+ * @param h_contract_terms hash of the contract to refund coin for
+ * @param refund_timestamp timestamp of the refund
+ * @param coin_pub public key of the coin to refund (fully)
+ * @param reason text justifying the refund
+ * @return transaction status
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a coin_pub is unknown to us;
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
+ * regardless of whether it actually increased the refund
*/
static enum GNUNET_DB_QueryStatus
-postgres_insert_contract_terms (
- void *cls,
- const char *instance_id,
- const char *order_id,
- json_t *contract_terms,
- uint64_t *order_serial)
+postgres_refund_coin (void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP
*h_contract_terms,
+ struct GNUNET_TIME_Timestamp refund_timestamp,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const char *reason)
{
struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp pay_deadline;
- struct GNUNET_TIME_Timestamp refund_deadline;
- const char *fulfillment_url;
- struct TALER_PrivateContractHashP h_contract_terms;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_timestamp (&refund_timestamp),
+ GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_string (reason),
+ GNUNET_PQ_query_param_end
+ };
- if (GNUNET_OK !=
- TALER_JSON_contract_hash (contract_terms,
- &h_contract_terms))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("pay_deadline",
- &pay_deadline),
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &refund_deadline),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (NULL,
- contract_terms,
- spec);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
-
- fulfillment_url =
- json_string_value (json_object_get (contract_terms,
- "fulfillment_url"));
- check_connection (pg);
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- TALER_PQ_query_param_json (contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&pay_deadline),
- GNUNET_PQ_query_param_timestamp (&refund_deadline),
- (NULL == fulfillment_url)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- order_serial),
- GNUNET_PQ_result_spec_end
- };
-
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "insert_contract_terms",
- params,
- rs);
- }
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "refund_coin",
+ params);
}
/**
- * Update the contract terms stored for @a order_id. Note that some attributes
are
- * expected to be calculated inside of the function, like the hash of the
- * contract terms (to be hashed), the creation_time and pay_deadline (to be
- * obtained from the merchant_orders table). The "session_id" should be
- * initially set to the empty string. The "fulfillment_url" and
"refund_deadline"
- * must be extracted from @a contract_terms.
+ * Retrieve contract terms given its @a order_id
*
* @param cls closure
* @param instance_id instance's identifier
- * @param order_id order_id used to store
- * @param contract_terms contract to store
- * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a
contract_terms
- * is malformed
+ * @param order_id order to lookup contract for
+ * @param[out] h_contract_terms set to the hash of the contract.
+ * @param[out] paid set to the payment status of the contract
+ * @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_update_contract_terms (void *cls,
- const char *instance_id,
- const char *order_id,
- json_t *contract_terms)
+postgres_lookup_order_status (
+ void *cls,
+ const char *instance_id,
+ const char *order_id,
+ struct TALER_PrivateContractHashP *h_contract_terms,
+ bool *paid)
{
struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Timestamp pay_deadline;
- struct GNUNET_TIME_Timestamp refund_deadline;
- const char *fulfillment_url = NULL;
- struct TALER_PrivateContractHashP h_contract_terms;
-
- if (GNUNET_OK !=
- TALER_JSON_contract_hash (contract_terms,
- &h_contract_terms))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_timestamp ("pay_deadline",
- &pay_deadline),
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &refund_deadline),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("fulfillment_url",
- &fulfillment_url),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (NULL,
- contract_terms,
- spec);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
+ uint8_t paid8;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_end
+ };
+ 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 ("paid",
+ &paid8),
+ GNUNET_PQ_result_spec_end
+ };
check_connection (pg);
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- TALER_PQ_query_param_json (contract_terms),
- GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&pay_deadline),
- GNUNET_PQ_query_param_timestamp (&refund_deadline),
- (NULL == fulfillment_url)
- ? GNUNET_PQ_query_param_null ()
- : GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_contract_terms",
- params);
- }
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_order_status",
+ params,
+ rs);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ *paid = (0 != paid8);
+ else
+ *paid = false; /* just to be safe(r) */
+ return qs;
}
/**
- * Delete information about a contract. Note that the transaction must
- * enforce that the contract is not awaiting payment anymore AND was not
- * paid, or is past the legal expiration.
+ * Retrieve contract terms given its @a order_serial
*
* @param cls closure
- * @param instance_id instance to delete order of
- * @param order_id order to delete
- * @param legal_expiration how long do we need to keep (paid) contracts on
- * file for legal reasons (i.e. taxation)
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if locks prevent deletion OR order unknown
+ * @param instance_id instance's identifier
+ * @param order_serial serial ID of the order to look up
+ * @param[out] order_id set to ID of the order
+ * @param[out] h_contract_terms set to the hash of the contract.
+ * @param[out] paid set to the payment status of the contract
+ * @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_delete_contract_terms (void *cls,
- const char *instance_id,
- const char *order_id,
- struct GNUNET_TIME_Relative legal_expiration)
+postgres_lookup_order_status_by_serial (void *cls,
+ const char *instance_id,
+ uint64_t order_serial,
+ char **order_id,
+ struct TALER_PrivateContractHashP *
+ h_contract_terms,
+ bool *paid)
{
struct PostgresClosure *pg = cls;
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ uint8_t paid8;
+ enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_relative_time (&legal_expiration),
- GNUNET_PQ_query_param_absolute_time (&now),
+ GNUNET_PQ_query_param_uint64 (&order_serial),
GNUNET_PQ_query_param_end
};
+ 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 ("paid",
+ &paid8),
+ GNUNET_PQ_result_spec_string ("order_id",
+ order_id),
+ GNUNET_PQ_result_spec_end
+ };
check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_contract_terms",
- params);
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+
"lookup_order_status_by_serial",
+ params,
+ rs);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ *paid = (0 != paid8);
+ else
+ *paid = false; /* just to be safe(r) */
+ return qs;
}
/**
- * Closure for #lookup_deposits_cb().
+ * Retrieve payment and wire status for a given @a order_serial and session ID.
+ *
+ * @param cls closure
+ * @param order_serial identifies the order
+ * @param session_id session for which to check the payment status, NULL for
any
+ * @param[out] paid set to the payment status of the contract
+ * @param[out] wired set to the wire transfer status of the exchange payment
+ * @return transaction status
*/
-struct LookupDepositsContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_payment_status (void *cls,
+ uint64_t order_serial,
+ const char *session_id,
+ bool *paid,
+ bool *wired)
+{
+ struct PostgresClosure *pg = cls;
+ uint8_t paid8;
+ uint8_t wired8;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("paid",
+ &paid8),
+ GNUNET_PQ_result_spec_auto_from_type ("wired",
+ &wired8),
+ GNUNET_PQ_result_spec_end
+ };
+ check_connection (pg);
+ if (NULL == session_id)
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&order_serial),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_payment_status",
+ params,
+ rs);
+ }
+ else
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&order_serial),
+ GNUNET_PQ_query_param_string (session_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+
"lookup_payment_status_session_id",
+ params,
+ rs);
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ *paid = (0 != paid8);
+ *wired = (0 != wired8);
+ }
+ else
+ {
+ *paid = false; /* just to be safe(r) */
+ *wired = false; /* just to be safe(r) */
+ }
+ return qs;
+}
+
+
+/**
+ * Closure for lookup_deposits_by_order_cb().
+ */
+struct LookupDepositsByOrderContext
{
+
/**
- * Function to call with results.
+ * Plugin context.
*/
- TALER_MERCHANTDB_DepositsCallback cb;
+ struct PostgresClosure *pg;
/**
- * Closure for @e cls.
+ * Function to call with all results.
*/
- void *cb_cls;
+ TALER_MERCHANTDB_DepositedCoinsCallback cb;
/**
- * Plugin context.
+ * Closure for @e cb.
*/
- struct PostgresClosure *pg;
+ void *cb_cls;
/**
- * Transaction status (set).
+ * Set to the query result.
*/
enum GNUNET_DB_QueryStatus qs;
};
@@ -1158,39 +1008,39 @@ struct LookupDepositsContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param[in,out] cls of type `struct LookupDepositsContext *`
+ * @param cls of type `struct LookupDepositsByOrderContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_deposits_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+lookup_deposits_by_order_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct LookupDepositsContext *ldc = cls;
- struct PostgresClosure *pg = ldc->pg;
+ struct LookupDepositsByOrderContext *ldoc = cls;
+ struct PostgresClosure *pg = ldoc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
+ uint64_t deposit_serial;
+ char *exchange_url;
+ struct TALER_MerchantWireHashP h_wire;
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;
struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("deposit_serial",
+ &deposit_serial),
GNUNET_PQ_result_spec_string ("exchange_url",
&exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
+ GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+ &h_wire),
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_auto_from_type ("coin_pub",
+ &coin_pub),
GNUNET_PQ_result_spec_end
};
@@ -1200,199 +1050,83 @@ lookup_deposits_cb (void *cls,
i))
{
GNUNET_break (0);
- ldc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ldoc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- ldc->cb (ldc->cb_cls,
- exchange_url,
- &coin_pub,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee);
- GNUNET_PQ_cleanup_result (rs);
+ ldoc->cb (ldoc->cb_cls,
+ deposit_serial,
+ exchange_url,
+ &h_wire,
+ &amount_with_fee,
+ &deposit_fee,
+ &coin_pub);
+ GNUNET_PQ_cleanup_result (rs); /* technically useless here */
}
- ldc->qs = num_results;
+ ldoc->qs = num_results;
}
/**
- * Lookup information about coins that were successfully deposited for a
- * given contract.
+ * Retrieve details about coins that were deposited for an order.
*
* @param cls closure
- * @param instance_id instance to lookup deposits for
- * @param h_contract_terms proposal data's hashcode
- * @param cb function to call with payment data
+ * @param order_serial identifies the order
+ * @param cb function to call for each deposited coin
* @param cb_cls closure for @a cb
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_DepositsCallback cb,
- void *cb_cls)
+postgres_lookup_deposits_by_order (void *cls,
+ uint64_t order_serial,
+ TALER_MERCHANTDB_DepositedCoinsCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
+ struct LookupDepositsByOrderContext ldoc = {
+ .pg = pg,
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_uint64 (&order_serial),
GNUNET_PQ_query_param_end
};
- struct LookupDepositsContext ldc = {
- .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 deposits for h_contract_terms '%s'\n",
- GNUNET_h2s (&h_contract_terms->hash));
- check_connection (pg);
qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_deposits",
+ "lookup_deposits_by_order",
params,
- &lookup_deposits_cb,
- &ldc);
- if (qs <= 0)
+ &lookup_deposits_by_order_cb,
+ &ldoc);
+ if (qs < 0)
return qs;
- return ldc.qs;
-}
-
-
-/**
- * Insert an exchange signing key into our database.
- *
- * @param cls closure
- * @param master_pub exchange master public key used for @a master_sig
- * @param exchange_pub exchange signing key to insert
- * @param start_date when does the signing key become valid
- * @param expire_date when does the signing key stop being used
- * @param end_date when does the signing key become void as proof
- * @param master_sig signature of @a master_pub over the @a exchange_pub and
the dates
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_exchange_signkey (
- void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp expire_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_MasterSignatureP *master_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (master_pub),
- GNUNET_PQ_query_param_auto_from_type (exchange_pub),
- GNUNET_PQ_query_param_timestamp (&start_date),
- GNUNET_PQ_query_param_timestamp (&expire_date),
- GNUNET_PQ_query_param_timestamp (&end_date),
- GNUNET_PQ_query_param_auto_from_type (master_sig),
- GNUNET_PQ_query_param_end
- };
-
- check_connection (pg);
- postgres_preflight (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_exchange_signkey",
- params);
-
+ return ldoc.qs;
}
/**
- * Insert payment confirmation from the exchange into the database.
- *
- * @param cls closure
- * @param instance_id instance to lookup deposits for
- * @param deposit_timestamp time when the exchange generated the deposit
confirmation
- * @param h_contract_terms proposal data's hashcode
- * @param coin_pub public key of the coin
- * @param exchange_url URL of the exchange that issued @a coin_pub
- * @param amount_with_fee amount the exchange will deposit for this coin
- * @param deposit_fee fee the exchange will charge for this coin
- * @param wire_fee wire fee the exchange charges
- * @param refund_fee fee the exchange charges to refund this coin
- * @param h_wire hash of the wire details of the target account of the merchant
- * @param exchange_sig signature from exchange that coin was accepted
- * @param exchange_pub signgin key that was used for @a exchange_sig
- * @return transaction status
+ * Closure for lookup_deposits_by_order_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_insert_deposit (
- void *cls,
- const char *instance_id,
- struct GNUNET_TIME_Timestamp deposit_timestamp,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const char *exchange_url,
- const struct TALER_Amount *amount_with_fee,
- const struct TALER_Amount *deposit_fee,
- const struct TALER_Amount *refund_fee,
- const struct TALER_Amount *wire_fee,
- const struct TALER_MerchantWireHashP *h_wire,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
+struct LookupTransferDetailsByOrderContext
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&deposit_timestamp), /* $3 */
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_string (exchange_url),
- TALER_PQ_query_param_amount (amount_with_fee), /* $6/$7 */
- TALER_PQ_query_param_amount (deposit_fee), /* $8, $9 */
- TALER_PQ_query_param_amount (refund_fee), /* $10, $11 */
- TALER_PQ_query_param_amount (wire_fee), /* $12, $13 */
- GNUNET_PQ_query_param_auto_from_type (h_wire), /* $14 */
- GNUNET_PQ_query_param_auto_from_type (exchange_sig), /* $15 */
- GNUNET_PQ_query_param_auto_from_type (exchange_pub), /* $16 */
- GNUNET_PQ_query_param_end
- };
-
- /* no preflight check here, run in transaction by caller! */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Storing deposit for instance `%s' h_contract_terms `%s',
coin_pub: `%s', amount_with_fee: %s\n",
- instance_id,
- GNUNET_h2s (&h_contract_terms->hash),
- TALER_B2S (coin_pub),
- TALER_amount2s (amount_with_fee));
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_deposit",
- params);
-}
-
-
-/**
- * Closure for #lookup_refunds_cb().
- */
-struct LookupRefundsContext
-{
/**
- * Function to call for each refund.
+ * Plugin context.
*/
- TALER_MERCHANTDB_RefundCallback rc;
+ struct PostgresClosure *pg;
/**
- * Closure for @e rc.
+ * Function to call with all results.
*/
- void *rc_cls;
+ TALER_MERCHANTDB_OrderTransferDetailsCallback cb;
/**
- * Plugin context.
+ * Closure for @e cb.
*/
- struct PostgresClosure *pg;
+ void *cb_cls;
/**
- * Transaction result.
+ * Set to the query result.
*/
enum GNUNET_DB_QueryStatus qs;
};
@@ -1402,27 +1136,42 @@ struct LookupRefundsContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct LookupRefundsContext *`
+ * @param cls of type `struct LookupTransferDetailsByOrderContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_refunds_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+lookup_transfer_details_by_order_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct LookupRefundsContext *lrc = cls;
- struct PostgresClosure *pg = lrc->pg;
+ struct LookupTransferDetailsByOrderContext *ltdo = cls;
+ struct PostgresClosure *pg = ltdo->pg;
for (unsigned int i = 0; i<num_results; i++)
{
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount refund_amount;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ char *exchange_url;
+ uint64_t deposit_serial;
+ struct GNUNET_TIME_Timestamp execution_time;
+ struct TALER_Amount deposit_value;
+ struct TALER_Amount deposit_fee;
+ uint8_t transfer_confirmed;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &refund_amount),
+ GNUNET_PQ_result_spec_uint64 ("deposit_serial",
+ &deposit_serial),
+ GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
+ &execution_time),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ GNUNET_PQ_result_spec_auto_from_type ("wtid",
+ &wtid),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+ &deposit_value),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+ &deposit_fee),
+ GNUNET_PQ_result_spec_auto_from_type ("transfer_confirmed",
+ &transfer_confirmed),
GNUNET_PQ_result_spec_end
};
@@ -1432,481 +1181,259 @@ lookup_refunds_cb (void *cls,
i))
{
GNUNET_break (0);
- lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ltdo->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- lrc->rc (lrc->rc_cls,
- &coin_pub,
- &refund_amount);
+ ltdo->cb (ltdo->cb_cls,
+ &wtid,
+ exchange_url,
+ execution_time,
+ &deposit_value,
+ &deposit_fee,
+ (0 != transfer_confirmed));
GNUNET_PQ_cleanup_result (rs); /* technically useless here */
}
- lrc->qs = num_results;
+ ltdo->qs = num_results;
}
/**
- * Obtain refunds associated with a contract.
+ * Retrieve wire transfer details for all deposits associated with
+ * a given @a order_serial.
*
- * @param cls closure, typically a connection to the db
- * @param instance_id instance to lookup refunds for
- * @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
+ * @param cls closure
+ * @param order_serial identifies the order
+ * @param cb function called with the wire transfer details
+ * @param cb_cls closure for @a cb
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_refunds (
+postgres_lookup_transfer_details_by_order (
void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_RefundCallback rc,
- void *rc_cls)
+ uint64_t order_serial,
+ TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
+ struct LookupTransferDetailsByOrderContext ltdo = {
+ .pg = pg,
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_uint64 (&order_serial),
GNUNET_PQ_query_param_end
};
- struct LookupRefundsContext lrc = {
- .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 of h_contract_terms %s at `%s'\n",
- GNUNET_h2s (&h_contract_terms->hash),
- instance_id);
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_refunds",
- params,
- &lookup_refunds_cb,
- &lrc);
- if (0 >= qs)
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "lookup_transfer_details_by_order",
+ params,
+ &lookup_transfer_details_by_order_cb,
+ <do);
+ if (qs < 0)
return qs;
- return lrc.qs;
+ return ltdo.qs;
}
/**
- * Mark contract as paid and store the current @a session_id
- * for which the contract was paid. Deletes the underlying order
- * and marks the locked stocks of the order as sold.
+ * Insert wire transfer details for a deposit.
*
* @param cls closure
- * @param instance_id instance to mark contract as paid for
- * @param h_contract_terms hash of the contract that is now paid
- * @param session_id the session that paid the contract
+ * @param deposit_serial serial number of the deposit
+ * @param dd deposit transfer data from the exchange to store
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_mark_contract_paid (
+postgres_insert_deposit_to_transfer (
void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- const char *session_id)
+ uint64_t deposit_serial,
+ const struct TALER_EXCHANGE_DepositData *dd)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_QueryParam uparams[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_uint64 (&deposit_serial),
+ TALER_PQ_query_param_amount (&dd->coin_contribution),
+ GNUNET_PQ_query_param_timestamp (&dd->execution_time),
+ GNUNET_PQ_query_param_auto_from_type (&dd->exchange_sig),
+ GNUNET_PQ_query_param_auto_from_type (&dd->exchange_pub),
+ GNUNET_PQ_query_param_auto_from_type (&dd->wtid),
GNUNET_PQ_query_param_end
};
- enum GNUNET_DB_QueryStatus qs;
- /* Session ID must always be given by the caller. */
- GNUNET_assert (NULL != session_id);
-
- /* no preflight check here, run in transaction by caller! */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Marking h_contract_terms '%s' of %s as paid for session `%s'\n",
- GNUNET_h2s (&h_contract_terms->hash),
- instance_id,
- session_id);
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "mark_contract_paid",
- params);
- if (qs <= 0)
- return qs;
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "mark_inventory_sold",
- uparams);
- if (qs < 0)
- return qs; /* 0: no inventory management, that's OK! */
- /* ON DELETE CASCADE deletes from merchant_order_locks */
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_completed_order",
- uparams);
+ "insert_deposit_to_transfer",
+ params);
}
/**
- * Function called during aborts to refund a coin. Marks the
- * respective coin as refunded.
+ * Set 'wired' status for an order to 'true'.
*
* @param cls closure
- * @param instance_id instance to refund payment for
- * @param h_contract_terms hash of the contract to refund coin for
- * @param refund_timestamp timestamp of the refund
- * @param coin_pub public key of the coin to refund (fully)
- * @param reason text justifying the refund
+ * @param order_serial serial number of the order
* @return transaction status
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a coin_pub is unknown to us;
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
- * regardless of whether it actually increased the refund
*/
static enum GNUNET_DB_QueryStatus
-postgres_refund_coin (void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP
*h_contract_terms,
- struct GNUNET_TIME_Timestamp refund_timestamp,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const char *reason)
+postgres_mark_order_wired (void *cls,
+ uint64_t order_serial)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_timestamp (&refund_timestamp),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_string (reason),
+ GNUNET_PQ_query_param_uint64 (&order_serial),
GNUNET_PQ_query_param_end
};
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "refund_coin",
+ "mark_order_wired",
params);
}
/**
- * Retrieve contract terms given its @a order_id
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order to lookup contract for
- * @param[out] h_contract_terms set to the hash of the contract.
- * @param[out] paid set to the payment status of the contract
- * @return transaction status
+ * Closure for #process_refund_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_status (
- void *cls,
- const char *instance_id,
- const char *order_id,
- struct TALER_PrivateContractHashP *h_contract_terms,
- bool *paid)
+struct FindRefundContext
{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
- GNUNET_PQ_query_param_end
- };
- 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 ("paid",
- &paid8),
- GNUNET_PQ_result_spec_end
- };
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_order_status",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- *paid = (0 != paid8);
- else
- *paid = false; /* just to be safe(r) */
- return qs;
-}
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+ /**
+ * Updated to reflect total amount refunded so far.
+ */
+ struct TALER_Amount refunded_amount;
-/**
- * Retrieve contract terms given its @a order_serial
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_serial serial ID of the order to look up
- * @param[out] order_id set to ID of the order
- * @param[out] h_contract_terms set to the hash of the contract.
- * @param[out] paid set to the payment status of the contract
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_status_by_serial (void *cls,
- const char *instance_id,
- uint64_t order_serial,
- char **order_id,
- struct TALER_PrivateContractHashP *
- h_contract_terms,
- bool *paid)
-{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
- 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 ("paid",
- &paid8),
- GNUNET_PQ_result_spec_string ("order_id",
- order_id),
- GNUNET_PQ_result_spec_end
- };
+ /**
+ * Set to the largest refund transaction ID encountered.
+ */
+ uint64_t max_rtransaction_id;
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-
"lookup_order_status_by_serial",
- params,
- rs);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- *paid = (0 != paid8);
- else
- *paid = false; /* just to be safe(r) */
- return qs;
-}
+ /**
+ * Set to true on hard errors.
+ */
+ bool err;
+};
/**
- * Retrieve payment and wire status for a given @a order_serial and session ID.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
*
- * @param cls closure
- * @param order_serial identifies the order
- * @param session_id session for which to check the payment status, NULL for
any
- * @param[out] paid set to the payment status of the contract
- * @param[out] wired set to the wire transfer status of the exchange payment
- * @return transaction status
+ * @param cls closure, our `struct FindRefundContext`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
*/
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_payment_status (void *cls,
- uint64_t order_serial,
- const char *session_id,
- bool *paid,
- bool *wired)
+static void
+process_refund_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
- uint8_t paid8;
- uint8_t wired8;
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("paid",
- &paid8),
- GNUNET_PQ_result_spec_auto_from_type ("wired",
- &wired8),
- GNUNET_PQ_result_spec_end
- };
- check_connection (pg);
- if (NULL == session_id)
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
+ struct FindRefundContext *ictx = cls;
+ struct PostgresClosure *pg = ictx->pg;
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_payment_status",
- params,
- rs);
- }
- else
+ for (unsigned int i = 0; i<num_results; i++)
{
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_string (session_id),
- GNUNET_PQ_query_param_end
+ /* Sum up existing refunds */
+ struct TALER_Amount acc;
+ uint64_t rtransaction_id;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+ &acc),
+ GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
+ &rtransaction_id),
+ GNUNET_PQ_result_spec_end
};
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-
"lookup_payment_status_session_id",
- params,
- rs);
- }
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- *paid = (0 != paid8);
- *wired = (0 != wired8);
- }
- else
- {
- *paid = false; /* just to be safe(r) */
- *wired = false; /* just to be safe(r) */
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ictx->err = true;
+ return;
+ }
+ if (0 >
+ TALER_amount_add (&ictx->refunded_amount,
+ &ictx->refunded_amount,
+ &acc))
+ {
+ GNUNET_break (0);
+ ictx->err = true;
+ return;
+ }
+ 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));
}
- return qs;
}
/**
- * Closure for lookup_deposits_by_order_cb().
+ * Closure for #process_deposits_for_refund_cb().
*/
-struct LookupDepositsByOrderContext
+struct InsertRefundContext
{
-
/**
- * Plugin context.
+ * Used to provide a connection to the db
*/
struct PostgresClosure *pg;
/**
- * Function to call with all results.
+ * Amount to which increase the refund for this contract
*/
- TALER_MERCHANTDB_DepositedCoinsCallback cb;
+ const struct TALER_Amount *refund;
/**
- * Closure for @e cb.
+ * Human-readable reason behind this refund
*/
- void *cb_cls;
+ const char *reason;
/**
- * Set to the query result.
+ * Transaction status code.
*/
- enum GNUNET_DB_QueryStatus qs;
+ enum TALER_MERCHANTDB_RefundStatus rs;
};
/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupDepositsByOrderContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_deposits_by_order_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupDepositsByOrderContext *ldoc = cls;
- struct PostgresClosure *pg = ldoc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- uint64_t deposit_serial;
- char *exchange_url;
- struct TALER_MerchantWireHashP h_wire;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("deposit_serial",
- &deposit_serial),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("h_wire",
- &h_wire),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &coin_pub),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ldoc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- ldoc->cb (ldoc->cb_cls,
- deposit_serial,
- exchange_url,
- &h_wire,
- &amount_with_fee,
- &deposit_fee,
- &coin_pub);
- GNUNET_PQ_cleanup_result (rs); /* technically useless here */
- }
- ldoc->qs = num_results;
-}
-
-
-/**
- * Retrieve details about coins that were deposited for an order.
- *
- * @param cls closure
- * @param order_serial identifies the order
- * @param cb function to call for each deposited coin
- * @param cb_cls closure for @a cb
- * @return transaction status
+ * Data extracted per coin.
*/
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits_by_order (void *cls,
- uint64_t order_serial,
- TALER_MERCHANTDB_DepositedCoinsCallback cb,
- void *cb_cls)
+struct RefundCoinData
{
- struct PostgresClosure *pg = cls;
- struct LookupDepositsByOrderContext ldoc = {
- .pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_deposits_by_order",
- params,
- &lookup_deposits_by_order_cb,
- &ldoc);
- if (qs < 0)
- return qs;
- return ldoc.qs;
-}
-
-/**
- * Closure for lookup_deposits_by_order_cb().
- */
-struct LookupTransferDetailsByOrderContext
-{
+ /**
+ * Public key of a coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
/**
- * Plugin context.
+ * Amount deposited for this coin.
*/
- struct PostgresClosure *pg;
+ struct TALER_Amount deposited_with_fee;
/**
- * Function to call with all results.
+ * Amount refunded already for this coin.
*/
- TALER_MERCHANTDB_OrderTransferDetailsCallback cb;
+ struct TALER_Amount refund_amount;
/**
- * Closure for @e cb.
+ * Order serial (actually not really per-coin).
*/
- void *cb_cls;
+ uint64_t order_serial;
/**
- * Set to the query result.
+ * Maximum rtransaction_id for this coin so far.
*/
- enum GNUNET_DB_QueryStatus qs;
+ uint64_t max_rtransaction_id;
+
};
@@ -1914,44 +1441,42 @@ struct LookupTransferDetailsByOrderContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct LookupTransferDetailsByOrderContext *`
+ * @param cls closure, our `struct InsertRefundContext`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_transfer_details_by_order_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+process_deposits_for_refund_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct LookupTransferDetailsByOrderContext *ltdo = cls;
- struct PostgresClosure *pg = ltdo->pg;
+ struct InsertRefundContext *ctx = cls;
+ struct PostgresClosure *pg = ctx->pg;
+ struct TALER_Amount current_refund;
+ struct RefundCoinData rcd[GNUNET_NZL (num_results)];
+ struct GNUNET_TIME_Timestamp now;
+ now = GNUNET_TIME_timestamp_get ();
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_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_WireTransferIdentifierRawP wtid;
- char *exchange_url;
- uint64_t deposit_serial;
- struct GNUNET_TIME_Timestamp execution_time;
- struct TALER_Amount deposit_value;
- struct TALER_Amount deposit_fee;
- uint8_t transfer_confirmed;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("deposit_serial",
- &deposit_serial),
- GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
- &execution_time),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_auto_from_type ("wtid",
- &wtid),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
- &deposit_value),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_auto_from_type ("transfer_confirmed",
- &transfer_confirmed),
- GNUNET_PQ_result_spec_end
- };
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &rcd[i].coin_pub),
+ GNUNET_PQ_result_spec_uint64 ("order_serial",
+ &rcd[i].order_serial),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+ &rcd[i].deposited_with_fee),
+ GNUNET_PQ_result_spec_end
+ };
+ struct FindRefundContext ictx = {
+ .pg = pg
+ };
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
@@ -1959,142 +1484,284 @@ lookup_transfer_details_by_order_cb (void *cls,
i))
{
GNUNET_break (0);
- ltdo->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
return;
}
- ltdo->cb (ltdo->cb_cls,
- &wtid,
- exchange_url,
- execution_time,
- &deposit_value,
- &deposit_fee,
- (0 != transfer_confirmed));
- GNUNET_PQ_cleanup_result (rs); /* technically useless here */
+
+ {
+ 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_set_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;
+ rcd[i].max_rtransaction_id = ictx.max_rtransaction_id;
+ 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));
}
- ltdo->qs = num_results;
+
+ 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 (0 >
+ TALER_amount_add (¤t_refund,
+ ¤t_refund,
+ increment))
+ {
+ GNUNET_break (0);
+ 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), /* already
inc'ed */
+ GNUNET_PQ_query_param_timestamp (&now),
+ 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;
+ return;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
+ return;
+ default:
+ ctx->rs = (enum TALER_MERCHANTDB_RefundStatus) qs;
+ break;
+ }
+ }
+
+ /* stop immediately if we are done */
+ if (0 == TALER_amount_cmp (ctx->refund,
+ ¤t_refund))
+ {
+ ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
+ return;
+ }
+ }
+
+ /**
+ * 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;
}
/**
- * Retrieve wire transfer details for all deposits associated with
- * a given @a order_serial.
+ * 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 order_serial identifies the order
- * @param cb function called with the wire transfer details
- * @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!)
*/
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_details_by_order (
- void *cls,
- uint64_t order_serial,
- TALER_MERCHANTDB_OrderTransferDetailsCallback 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;
- struct LookupTransferDetailsByOrderContext ltdo = {
- .pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
- };
+ enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (order_id),
GNUNET_PQ_query_param_end
};
- enum GNUNET_DB_QueryStatus qs;
+ struct InsertRefundContext ctx = {
+ .pg = pg,
+ .refund = refund,
+ .reason = reason
+ };
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_transfer_details_by_order",
- params,
- &lookup_transfer_details_by_order_cb,
- <do);
- if (qs < 0)
- return qs;
- return ltdo.qs;
-}
-
-
-/**
- * Insert wire transfer details for a deposit.
- *
- * @param cls closure
- * @param deposit_serial serial number of the deposit
- * @param dd deposit transfer data from the exchange to store
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_deposit_to_transfer (
- void *cls,
- uint64_t deposit_serial,
- const struct TALER_EXCHANGE_DepositData *dd)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&deposit_serial),
- TALER_PQ_query_param_amount (&dd->coin_contribution),
- GNUNET_PQ_query_param_timestamp (&dd->execution_time),
- GNUNET_PQ_query_param_auto_from_type (&dd->exchange_sig),
- GNUNET_PQ_query_param_auto_from_type (&dd->exchange_pub),
- GNUNET_PQ_query_param_auto_from_type (&dd->wtid),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_deposit_to_transfer",
- params);
-}
-
-
-/**
- * Set 'wired' status for an order to 'true'.
- *
- * @param cls closure
- * @param order_serial serial number of the order
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_mark_order_wired (void *cls,
- uint64_t order_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&order_serial),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "mark_order_wired",
- params);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Asked to refund %s on order %s\n",
+ TALER_amount2s (refund),
+ order_id);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "find_deposits_for_refund",
+ 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 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 #process_refund_cb().
+ * Closure for #lookup_refunds_detailed_cb().
*/
-struct FindRefundContext
+struct LookupRefundsDetailedContext
{
-
/**
- * Plugin context.
+ * Function to call for each refund.
*/
- struct PostgresClosure *pg;
+ TALER_MERCHANTDB_RefundDetailCallback rc;
/**
- * Updated to reflect total amount refunded so far.
+ * Closure for @e rc.
*/
- struct TALER_Amount refunded_amount;
+ void *rc_cls;
/**
- * Set to the largest refund transaction ID encountered.
+ * Plugin context.
*/
- uint64_t max_rtransaction_id;
+ struct PostgresClosure *pg;
/**
- * Set to true on hard errors.
+ * Transaction result.
*/
- bool err;
+ enum GNUNET_DB_QueryStatus qs;
};
@@ -2102,28 +1769,45 @@ 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 GetRefundsContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-process_refund_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+lookup_refunds_detailed_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct FindRefundContext *ictx = cls;
- struct PostgresClosure *pg = ictx->pg;
+ struct LookupRefundsDetailedContext *lrdc = cls;
+ struct PostgresClosure *pg = lrdc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
- /* Sum up existing refunds */
- struct TALER_Amount acc;
+ uint64_t refund_serial;
+ struct GNUNET_TIME_Timestamp timestamp;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
uint64_t rtransaction_id;
+ struct TALER_Amount refund_amount;
+ char *reason;
+ char *exchange_url;
+ uint8_t pending8;
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &acc),
+ GNUNET_PQ_result_spec_uint64 ("refund_serial",
+ &refund_serial),
+ GNUNET_PQ_result_spec_timestamp ("refund_timestamp",
+ ×tamp),
+ 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),
+ GNUNET_PQ_result_spec_string ("reason",
+ &reason),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+ &refund_amount),
+ GNUNET_PQ_result_spec_auto_from_type ("pending",
+ &pending8),
GNUNET_PQ_result_spec_end
};
@@ -2133,1040 +1817,946 @@ process_refund_cb (void *cls,
i))
{
GNUNET_break (0);
- ictx->err = true;
- return;
- }
- if (0 >
- TALER_amount_add (&ictx->refunded_amount,
- &ictx->refunded_amount,
- &acc))
- {
- GNUNET_break (0);
- ictx->err = true;
+ lrdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- 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));
+ lrdc->rc (lrdc->rc_cls,
+ refund_serial,
+ timestamp,
+ &coin_pub,
+ exchange_url,
+ rtransaction_id,
+ reason,
+ &refund_amount,
+ 0 != pending8);
+ GNUNET_PQ_cleanup_result (rs);
}
+ lrdc->qs = num_results;
}
/**
- * Closure for #process_deposits_for_refund_cb().
+ * Obtain detailed refund data associated with a contract.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param instance_id instance to lookup refunds for
+ * @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
*/
-struct InsertRefundContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_refunds_detailed (
+ void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ TALER_MERCHANTDB_RefundDetailCallback rc,
+ void *rc_cls)
{
- /**
- * Used to provide a connection to the db
- */
- struct PostgresClosure *pg;
-
- /**
- * Amount to which increase the refund for this contract
- */
- const struct TALER_Amount *refund;
-
- /**
- * Human-readable reason behind this refund
- */
- const char *reason;
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_end
+ };
+ struct LookupRefundsDetailedContext lrdc = {
+ .rc = rc,
+ .rc_cls = rc_cls,
+ .pg = pg
+ };
+ enum GNUNET_DB_QueryStatus qs;
- /**
- * Transaction status code.
- */
- enum TALER_MERCHANTDB_RefundStatus rs;
-};
+ /* no preflight check here, run in transaction by caller! */
+ TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
+ GNUNET_h2s (&h_contract_terms->hash),
+ instance_id);
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_refunds_detailed",
+ params,
+ &lookup_refunds_detailed_cb,
+ &lrdc);
+ if (0 >= qs)
+ return qs;
+ return lrdc.qs;
+}
/**
- * Data extracted per coin.
+ * Insert refund proof data from the exchange into the database.
+ *
+ * @param cls closure
+ * @param refund_serial serial number of the refund
+ * @param exchange_sig signature from exchange that coin was refunded
+ * @param exchange_pub signing key that was used for @a exchange_sig
+ * @return transaction status
*/
-struct RefundCoinData
+static enum GNUNET_DB_QueryStatus
+postgres_insert_refund_proof (
+ void *cls,
+ uint64_t refund_serial,
+ const struct TALER_ExchangeSignatureP *exchange_sig,
+ const struct TALER_ExchangePublicKeyP *exchange_pub)
{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&refund_serial),
+ GNUNET_PQ_query_param_auto_from_type (exchange_sig),
+ GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+ GNUNET_PQ_query_param_end
+ };
- /**
- * Public key of a coin.
- */
- struct TALER_CoinSpendPublicKeyP coin_pub;
-
- /**
- * Amount deposited for this coin.
- */
- struct TALER_Amount deposited_with_fee;
-
- /**
- * Amount refunded already for this coin.
- */
- struct TALER_Amount refund_amount;
-
- /**
- * Order serial (actually not really per-coin).
- */
- uint64_t order_serial;
-
- /**
- * Maximum rtransaction_id for this coin so far.
- */
- uint64_t max_rtransaction_id;
-
-};
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_refund_proof",
+ params);
+}
/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * Lookup refund proof data.
*
- * @param cls closure, our `struct InsertRefundContext`
- * @param result the postgres result
- * @param num_results the number of results in @a result
+ * @param cls closure
+ * @param refund_serial serial number of the refund
+ * @param[out] exchange_sig set to signature from exchange
+ * @param[out] exchange_pub signing key that was used for @a exchange_sig
+ * @return transaction status
*/
-static void
-process_deposits_for_refund_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_refund_proof (void *cls,
+ uint64_t refund_serial,
+ struct TALER_ExchangeSignatureP *exchange_sig,
+ struct TALER_ExchangePublicKeyP *exchange_pub)
{
- struct InsertRefundContext *ctx = cls;
- struct PostgresClosure *pg = ctx->pg;
- struct TALER_Amount current_refund;
- struct RefundCoinData rcd[GNUNET_NZL (num_results)];
- struct GNUNET_TIME_Timestamp now;
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&refund_serial),
+ 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
+ };
- now = GNUNET_TIME_timestamp_get ();
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_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 GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &rcd[i].coin_pub),
- GNUNET_PQ_result_spec_uint64 ("order_serial",
- &rcd[i].order_serial),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &rcd[i].deposited_with_fee),
- GNUNET_PQ_result_spec_end
- };
- struct FindRefundContext ictx = {
- .pg = pg
- };
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_refund_proof",
+ params,
+ rs);
+}
- 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
- };
+/**
+ * Retrieve the order ID that was used to pay for a resource within a session.
+ *
+ * @param cls closure
+ * @param instance_id identifying the instance
+ * @param fulfillment_url URL that canonically identifies the resource
+ * being paid for
+ * @param session_id session id
+ * @param[out] order_id where to store the order ID that was used when
+ * paying for the resource URL
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+postgres_lookup_order_by_fulfillment (void *cls,
+ const char *instance_id,
+ const char *fulfillment_url,
+ const char *session_id,
+ char **order_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (fulfillment_url),
+ GNUNET_PQ_query_param_string (session_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("order_id",
+ order_id),
+ GNUNET_PQ_result_spec_end
+ };
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (ctx->refund->currency,
- &ictx.refunded_amount));
- ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
- "find_refunds_by_coin",
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+
"lookup_order_by_fulfillment",
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;
- rcd[i].max_rtransaction_id = ictx.max_rtransaction_id;
- 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));
+ rs);
+}
- /* 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;
+/**
+ * Insert information about a wire transfer the merchant has received.
+ *
+ * @param cls closure
+ * @param instance_id the instance that received the transfer
+ * @param exchange_url which exchange made the transfer
+ * @param wtid identifier of the wire transfer
+ * @param credit_amount how much did we receive
+ * @param payto_uri what is the merchant's bank account that received the
transfer
+ * @param confirmed whether the transfer was confirmed by the merchant or
+ * was merely claimed by the exchange at this point
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_transfer (
+ void *cls,
+ const char *instance_id,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_Amount *credit_amount,
+ const char *payto_uri,
+ bool confirmed)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ TALER_PQ_query_param_amount (credit_amount),
+ GNUNET_PQ_query_param_string (payto_uri),
+ GNUNET_PQ_query_param_bool (confirmed),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_end
+ };
- /* 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;
- }
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_transfer",
+ params);
+}
- 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 (0 >
- TALER_amount_add (¤t_refund,
- ¤t_refund,
- increment))
- {
- GNUNET_break (0);
- 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), /* already
inc'ed */
- GNUNET_PQ_query_param_timestamp (&now),
- 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;
- return;
- case GNUNET_DB_STATUS_SOFT_ERROR:
- ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
- return;
- default:
- ctx->rs = (enum TALER_MERCHANTDB_RefundStatus) qs;
- break;
- }
- }
-
- /* stop immediately if we are done */
- if (0 == TALER_amount_cmp (ctx->refund,
- ¤t_refund))
- {
- ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
- return;
- }
- }
+/**
+ * Delete information about a transfer. Note that transfers
+ * confirmed by the exchange cannot be deleted anymore.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete transfer of
+ * @param transfer_serial_id transfer to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if deletion is prohibited OR transfer is unknown
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_delete_transfer (void *cls,
+ const char *instance_id,
+ uint64_t transfer_serial_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
+ 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->rs = TALER_MERCHANTDB_RS_TOO_HIGH;
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_transfer",
+ 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.
+ * Check if information about a transfer exists with the
+ * backend. Returns no data, only the query status.
*
* @param cls closure
- * @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!)
+ * @param instance_id instance to delete transfer of
+ * @param transfer_serial_id transfer to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
+ * if the transfer record exists
*/
-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)
+static enum GNUNET_DB_QueryStatus
+postgres_check_transfer_exists (void *cls,
+ const char *instance_id,
+ uint64_t transfer_serial_id)
{
struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (order_id),
+ GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
GNUNET_PQ_query_param_end
};
- struct InsertRefundContext ctx = {
- .pg = pg,
- .refund = refund,
- .reason = reason
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_end
};
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to refund %s on order %s\n",
- TALER_amount2s (refund),
- order_id);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "find_deposits_for_refund",
- 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 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;
- }
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "check_transfer_exists",
+ params,
+ rs);
}
/**
- * Closure for #lookup_refunds_detailed_cb().
+ * Lookup account serial by payto URI.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup the account from
+ * @param payto_uri what is the merchant's bank account to lookup
+ * @param[out] account_serial serial number of the account
+ * @return transaction status
*/
-struct LookupRefundsDetailedContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_account (void *cls,
+ const char *instance_id,
+ const char *payto_uri,
+ uint64_t *account_serial)
{
- /**
- * Function to call for each refund.
- */
- TALER_MERCHANTDB_RefundDetailCallback rc;
-
- /**
- * Closure for @e rc.
- */
- void *rc_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (payto_uri),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("account_serial",
+ account_serial),
+ GNUNET_PQ_result_spec_end
+ };
- /**
- * Transaction result.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_account",
+ params,
+ rs);
+}
/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * Insert information about a wire transfer the merchant has received.
*
- * @param cls of type `struct GetRefundsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
+ * @param cls closure
+ * @param instance_id instance to provide transfer details for
+ * @param exchange_url which exchange made the transfer
+ * @param payto_uri what is the merchant's bank account that received the
transfer
+ * @param wtid identifier of the wire transfer
+ * @param td transfer details to store
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the @a wtid and @a exchange_uri
are not known for this @a instance_id
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
*/
-static void
-lookup_refunds_detailed_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupRefundsDetailedContext *lrdc = cls;
- struct PostgresClosure *pg = lrdc->pg;
-
- for (unsigned int i = 0; i<num_results; i++)
- {
- uint64_t refund_serial;
- struct GNUNET_TIME_Timestamp timestamp;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- uint64_t rtransaction_id;
- struct TALER_Amount refund_amount;
- char *reason;
- char *exchange_url;
- uint8_t pending8;
+static enum GNUNET_DB_QueryStatus
+postgres_insert_transfer_details (
+ void *cls,
+ const char *instance_id,
+ const char *exchange_url,
+ const char *payto_uri,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const struct TALER_EXCHANGE_TransferData *td)
+{
+ struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ uint64_t credit_serial;
+ unsigned int retries;
+
+ retries = 0;
+ check_connection (pg);
+RETRY:
+ if (MAX_RETRIES < ++retries)
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+ if (GNUNET_OK !=
+ postgres_start_read_committed (pg,
+ "insert transfer details"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ /* lookup credit serial */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_string (payto_uri),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
+ GNUNET_PQ_query_param_end
+ };
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("refund_serial",
- &refund_serial),
- GNUNET_PQ_result_spec_timestamp ("refund_timestamp",
- ×tamp),
- 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),
- GNUNET_PQ_result_spec_string ("reason",
- &reason),
- TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
- &refund_amount),
- GNUNET_PQ_result_spec_auto_from_type ("pending",
- &pending8),
+ GNUNET_PQ_result_spec_uint64 ("credit_serial",
+ &credit_serial),
GNUNET_PQ_result_spec_end
};
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_credit_serial",
+ params,
+ rs);
+ if (0 > qs)
{
- GNUNET_break (0);
- lrdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "'lookup_credit_serial' for account %s and amount %s failed
with status %d\n",
+ payto_uri,
+ TALER_amount2s (&td->total_amount),
+ qs);
+ return qs;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ postgres_rollback (pg);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "'lookup_credit_serial' for account %s failed with transfer
unknown\n",
+ payto_uri);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
- lrdc->rc (lrdc->rc_cls,
- refund_serial,
- timestamp,
- &coin_pub,
- exchange_url,
- rtransaction_id,
- reason,
- &refund_amount,
- 0 != pending8);
- GNUNET_PQ_cleanup_result (rs);
}
- lrdc->qs = num_results;
+
+ /* update merchant_transfer_signatures table */
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&credit_serial),
+ TALER_PQ_query_param_amount (&td->total_amount),
+ TALER_PQ_query_param_amount (&td->wire_fee),
+ GNUNET_PQ_query_param_timestamp (&td->execution_time),
+ GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
+ GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_transfer_signature",
+ params);
+ if (0 > qs)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "'insert_transfer_signature' failed with status %d\n",
+ qs);
+ return qs;
+ }
+ if (0 == qs)
+ {
+ postgres_rollback (pg);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "'insert_transfer_signature' failed with status %d\n",
+ qs);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ }
+
+ /* Update transfer-coin association table */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Updating transfer-coin association table\n");
+ for (unsigned int i = 0; i<td->details_length; i++)
+ {
+ const struct TALER_TrackTransferDetails *d = &td->details[i];
+ uint64_t i64 = (uint64_t) i;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&credit_serial),
+ GNUNET_PQ_query_param_uint64 (&i64),
+ TALER_PQ_query_param_amount (&d->coin_value),
+ TALER_PQ_query_param_amount (&d->coin_fee), /* deposit fee */
+ GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
+ GNUNET_PQ_query_param_auto_from_type (&d->h_contract_terms),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_transfer_to_coin_mapping",
+ params);
+ if (0 > qs)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "'insert_transfer_to_coin_mapping' failed with status %d\n",
+ qs);
+ return qs;
+ }
+ if (0 == qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "'insert_transfer_to_coin_mapping' failed at %u: deposit
unknown\n",
+ i);
+ }
+ }
+ /* Update merchant_contract_terms 'wired' status: for all coins
+ that were wired, set the respective order's "wired" status to
+ true, *if* all other deposited coins associated with that order
+ have also been wired (this time or earlier) */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Updating contract terms 'wired' status\n");
+ for (unsigned int i = 0; i<td->details_length; i++)
+ {
+ const struct TALER_TrackTransferDetails *d = &td->details[i];
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_wired_by_coin_pub",
+ params);
+ if (0 > qs)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "'update_wired_by_coin_pub' failed with status %d\n",
+ qs);
+ return qs;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Committing transaction...\n");
+ qs = postgres_commit (pg);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return qs;
}
/**
- * Obtain detailed refund data associated with a contract.
+ * Obtain information about wire fees charged by an exchange,
+ * including signature (so we have proof).
*
- * @param cls closure, typically a connection to the db
- * @param instance_id instance to lookup refunds for
- * @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
+ * @param cls closure
+ * @param master_pub public key of the exchange
+ * @param wire_method the wire method
+ * @param contract_date date of the contract to use for the lookup
+ * @param[out] fees wire fees charged
+ * @param[out] start_date start of fee being used
+ * @param[out] end_date end of fee being used
+ * @param[out] master_sig signature of exchange over fee structure
+ * @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_refunds_detailed (
- void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- TALER_MERCHANTDB_RefundDetailCallback rc,
- void *rc_cls)
+postgres_lookup_wire_fee (void *cls,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ const char *wire_method,
+ struct GNUNET_TIME_Timestamp contract_date,
+ struct TALER_WireFeeSet *fees,
+ struct GNUNET_TIME_Timestamp *start_date,
+ struct GNUNET_TIME_Timestamp *end_date,
+ struct TALER_MasterSignatureP *master_sig)
{
struct PostgresClosure *pg = cls;
+ struct GNUNET_HashCode h_wire_method;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+ GNUNET_PQ_query_param_auto_from_type (&h_wire_method),
+ GNUNET_PQ_query_param_timestamp (&contract_date),
GNUNET_PQ_query_param_end
};
- struct LookupRefundsDetailedContext lrdc = {
- .rc = rc,
- .rc_cls = rc_cls,
- .pg = pg
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ &fees->wire),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
+ &fees->closing),
+ GNUNET_PQ_result_spec_timestamp ("start_date",
+ start_date),
+ GNUNET_PQ_result_spec_timestamp ("end_date",
+ end_date),
+ GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+ master_sig),
+ GNUNET_PQ_result_spec_end
};
- 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->hash),
- instance_id);
check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_refunds_detailed",
- params,
- &lookup_refunds_detailed_cb,
- &lrdc);
- if (0 >= qs)
- return qs;
- return lrdc.qs;
+ GNUNET_CRYPTO_hash (wire_method,
+ strlen (wire_method) + 1,
+ &h_wire_method);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_wire_fee",
+ params,
+ rs);
}
/**
- * Insert refund proof data from the exchange into the database.
- *
- * @param cls closure
- * @param refund_serial serial number of the refund
- * @param exchange_sig signature from exchange that coin was refunded
- * @param exchange_pub signing key that was used for @a exchange_sig
- * @return transaction status
+ * Closure for #lookup_deposits_by_contract_and_coin_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_insert_refund_proof (
- void *cls,
- uint64_t refund_serial,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
+struct LookupDepositsByCnCContext
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&refund_serial),
- 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 for each deposit.
+ */
+ TALER_MERCHANTDB_CoinDepositCallback cb;
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_refund_proof",
- params);
-}
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Transaction result.
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
/**
- * Lookup refund proof data.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
*
- * @param cls closure
- * @param refund_serial serial number of the refund
- * @param[out] exchange_sig set to signature from exchange
- * @param[out] exchange_pub signing key that was used for @a exchange_sig
- * @return transaction status
+ * @param cls of type `struct LookupDepositsByCnCContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
*/
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_refund_proof (void *cls,
- uint64_t refund_serial,
- struct TALER_ExchangeSignatureP *exchange_sig,
- struct TALER_ExchangePublicKeyP *exchange_pub)
+static void
+lookup_deposits_by_contract_and_coin_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&refund_serial),
- 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 LookupDepositsByCnCContext *ldcc = cls;
+ struct PostgresClosure *pg = ldcc->pg;
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_refund_proof",
- params,
- rs);
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ char *exchange_url;
+ struct TALER_Amount amount_with_fee;
+ struct TALER_Amount deposit_fee;
+ struct TALER_Amount refund_fee;
+ struct TALER_Amount wire_fee;
+ struct TALER_MerchantWireHashP h_wire;
+ struct GNUNET_TIME_Timestamp deposit_timestamp;
+ struct GNUNET_TIME_Timestamp refund_deadline;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ 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_auto_from_type ("h_wire",
+ &h_wire),
+ GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
+ &deposit_timestamp),
+ GNUNET_PQ_result_spec_timestamp ("refund_deadline",
+ &refund_deadline),
+ 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
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ldcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ ldcc->cb (ldcc->cb_cls,
+ exchange_url,
+ &amount_with_fee,
+ &deposit_fee,
+ &refund_fee,
+ &wire_fee,
+ &h_wire,
+ deposit_timestamp,
+ refund_deadline,
+ &exchange_sig,
+ &exchange_pub);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+ ldcc->qs = num_results;
}
/**
- * Retrieve the order ID that was used to pay for a resource within a session.
+ * Lookup information about coin payments by @a h_contract_terms and
+ * @a coin_pub.
*
* @param cls closure
- * @param instance_id identifying the instance
- * @param fulfillment_url URL that canonically identifies the resource
- * being paid for
- * @param session_id session id
- * @param[out] order_id where to store the order ID that was used when
- * paying for the resource URL
+ * @param instance_id instance to lookup payments for
+ * @param h_contract_terms proposal data's hashcode
+ * @param coin_pub public key to use for the search
+ * @param cb function to call with payment data
+ * @param cb_cls closure for @a cb
* @return transaction status
*/
-enum GNUNET_DB_QueryStatus
-postgres_lookup_order_by_fulfillment (void *cls,
- const char *instance_id,
- const char *fulfillment_url,
- const char *session_id,
- char **order_id)
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_deposits_by_contract_and_coin (
+ void *cls,
+ const char *instance_id,
+ const struct TALER_PrivateContractHashP *h_contract_terms,
+ 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_string (instance_id),
- GNUNET_PQ_query_param_string (fulfillment_url),
- GNUNET_PQ_query_param_string (session_id),
+ GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+ GNUNET_PQ_query_param_auto_from_type (coin_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
+ struct LookupDepositsByCnCContext ldcc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
};
+ enum GNUNET_DB_QueryStatus qs;
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-
"lookup_order_by_fulfillment",
- params,
- rs);
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "lookup_deposits_by_contract_and_coin",
+ params,
+ &lookup_deposits_by_contract_and_coin_cb,
+ &ldcc);
+ if (0 >= qs)
+ return qs;
+ return ldcc.qs;
}
/**
- * Insert information about a wire transfer the merchant has received.
+ * Lookup transfer status.
*
* @param cls closure
- * @param instance_id the instance that received the transfer
- * @param exchange_url which exchange made the transfer
- * @param wtid identifier of the wire transfer
- * @param credit_amount how much did we receive
- * @param payto_uri what is the merchant's bank account that received the
transfer
- * @param confirmed whether the transfer was confirmed by the merchant or
- * was merely claimed by the exchange at this point
+ * @param instance_id at which instance should we resolve the transfer
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param[out] total_amount amount that was debited from our
+ * aggregate balance at the exchange (in total, sum of
+ * the wire transfer amount and the @a wire_fee)
+ * @param[out] wire_fee the wire fee the exchange charged (only set if @a
have_exchange_sig is true)
+ * @param[out] exchange_amount the amount the exchange claims was transferred
(only set if @a have_exchange_sig is true)
+ * @param[out] execution_time when the transfer was executed by the exchange
(only set if @a have_exchange_sig is true)
+ * @param[out] have_exchange_sig do we have a response from the exchange about
this transfer
+ * @param[out] verified did we confirm the transfer was OK
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_insert_transfer (
+postgres_lookup_transfer (
void *cls,
const char *instance_id,
const char *exchange_url,
const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *credit_amount,
- const char *payto_uri,
- bool confirmed)
+ struct TALER_Amount *total_amount,
+ struct TALER_Amount *wire_fee,
+ struct TALER_Amount *exchange_amount,
+ struct GNUNET_TIME_Timestamp *execution_time,
+ bool *have_exchange_sig,
+ bool *verified)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (exchange_url),
GNUNET_PQ_query_param_auto_from_type (wtid),
- TALER_PQ_query_param_amount (credit_amount),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_bool (confirmed),
GNUNET_PQ_query_param_string (instance_id),
GNUNET_PQ_query_param_end
};
+ uint8_t verified8;
+ /** Amount we got actually credited, _excludes_ the wire fee */
+ bool no_sig;
+ struct TALER_Amount credit_amount;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
+ &credit_amount),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+ wire_fee),
+ &no_sig),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_amount",
+ exchange_amount),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_timestamp ("execution_time",
+ execution_time),
+ NULL),
+ GNUNET_PQ_result_spec_auto_from_type ("verified",
+ &verified8),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer",
- params);
+ *execution_time = GNUNET_TIME_UNIT_ZERO_TS;
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_transfer",
+ params,
+ rs);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Lookup transfer returned %d\n",
+ qs);
+ if (qs > 0)
+ {
+ *have_exchange_sig = ! no_sig;
+ *verified = (0 != verified8);
+ if ( (! no_sig) &&
+ (0 >
+ TALER_amount_add (total_amount,
+ &credit_amount,
+ wire_fee)) )
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ }
+ else
+ {
+ *verified = false;
+ *have_exchange_sig = false;
+ }
+ return qs;
}
/**
- * Delete information about a transfer. Note that transfers
- * confirmed by the exchange cannot be deleted anymore.
- *
- * @param cls closure
- * @param instance_id instance to delete transfer of
- * @param transfer_serial_id transfer to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- * if deletion is prohibited OR transfer is unknown
+ * Closure for #lookup_transfer_summary_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_delete_transfer (void *cls,
- const char *instance_id,
- uint64_t transfer_serial_id)
+struct LookupTransferSummaryContext
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
- GNUNET_PQ_query_param_end
- };
+ /**
+ * Function to call for each order that was aggregated.
+ */
+ TALER_MERCHANTDB_TransferSummaryCallback cb;
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "delete_transfer",
- params);
-}
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Plugin context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Transaction result.
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
/**
- * Check if information about a transfer exists with the
- * backend. Returns no data, only the query status.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
*
- * @param cls closure
- * @param instance_id instance to delete transfer of
- * @param transfer_serial_id transfer to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
- * if the transfer record exists
+ * @param cls of type `struct LookupTransferSummaryContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
*/
-static enum GNUNET_DB_QueryStatus
-postgres_check_transfer_exists (void *cls,
- const char *instance_id,
- uint64_t transfer_serial_id)
+static void
+lookup_transfer_summary_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_end
- };
+ struct LookupTransferSummaryContext *ltdc = cls;
+ struct PostgresClosure *pg = ltdc->pg;
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "check_transfer_exists",
- params,
- rs);
+ for (unsigned int i = 0; i<num_results; i++)
+ {
+ char *order_id;
+ struct TALER_Amount deposit_value;
+ struct TALER_Amount deposit_fee;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("order_id",
+ &order_id),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+ &deposit_value),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+ &deposit_fee),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ ltdc->cb (ltdc->cb_cls,
+ order_id,
+ &deposit_value,
+ &deposit_fee);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+ ltdc->qs = num_results;
}
/**
- * Lookup account serial by payto URI.
+ * Lookup transfer summary.
*
* @param cls closure
- * @param instance_id instance to lookup the account from
- * @param payto_uri what is the merchant's bank account to lookup
- * @param[out] account_serial serial number of the account
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param cb function to call with detailed transfer data
+ * @param cb_cls closure for @a cb
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_account (void *cls,
- const char *instance_id,
- const char *payto_uri,
- uint64_t *account_serial)
+postgres_lookup_transfer_summary (
+ void *cls,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MERCHANTDB_TransferSummaryCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_string (payto_uri),
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end
};
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("account_serial",
- account_serial),
- GNUNET_PQ_result_spec_end
+ struct LookupTransferSummaryContext ltdc = {
+ .cb = cb,
+ .cb_cls = cb_cls,
+ .pg = pg
};
+ enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_account",
- params,
- rs);
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "lookup_transfer_summary",
+ params,
+ &lookup_transfer_summary_cb,
+ <dc);
+ if (0 >= qs)
+ return qs;
+ return ltdc.qs;
}
/**
- * Insert information about a wire transfer the merchant has received.
- *
- * @param cls closure
- * @param instance_id instance to provide transfer details for
- * @param exchange_url which exchange made the transfer
- * @param payto_uri what is the merchant's bank account that received the
transfer
- * @param wtid identifier of the wire transfer
- * @param td transfer details to store
- * @return transaction status,
- * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the @a wtid and @a exchange_uri
are not known for this @a instance_id
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
+ * Closure for #lookup_transfer_details_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_insert_transfer_details (
- void *cls,
- const char *instance_id,
- const char *exchange_url,
- const char *payto_uri,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_EXCHANGE_TransferData *td)
+struct LookupTransferDetailsContext
{
- struct PostgresClosure *pg = cls;
- enum GNUNET_DB_QueryStatus qs;
- uint64_t credit_serial;
- unsigned int retries;
-
- retries = 0;
- check_connection (pg);
-RETRY:
- if (MAX_RETRIES < ++retries)
- return GNUNET_DB_STATUS_SOFT_ERROR;
- if (GNUNET_OK !=
- postgres_start_read_committed (pg,
- "insert transfer details"))
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- /* lookup credit serial */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_string (payto_uri),
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (wtid),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("credit_serial",
- &credit_serial),
- GNUNET_PQ_result_spec_end
- };
-
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_credit_serial",
- params,
- rs);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'lookup_credit_serial' for account %s and amount %s failed
with status %d\n",
- payto_uri,
- TALER_amount2s (&td->total_amount),
- qs);
- return qs;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- postgres_rollback (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'lookup_credit_serial' for account %s failed with transfer
unknown\n",
- payto_uri);
- return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
- }
- }
-
- /* update merchant_transfer_signatures table */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&credit_serial),
- TALER_PQ_query_param_amount (&td->total_amount),
- TALER_PQ_query_param_amount (&td->wire_fee),
- GNUNET_PQ_query_param_timestamp (&td->execution_time),
- GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
- GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer_signature",
- params);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'insert_transfer_signature' failed with status %d\n",
- qs);
- return qs;
- }
- if (0 == qs)
- {
- postgres_rollback (pg);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'insert_transfer_signature' failed with status %d\n",
- qs);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
-
- /* Update transfer-coin association table */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Updating transfer-coin association table\n");
- for (unsigned int i = 0; i<td->details_length; i++)
- {
- const struct TALER_TrackTransferDetails *d = &td->details[i];
- uint64_t i64 = (uint64_t) i;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_uint64 (&credit_serial),
- GNUNET_PQ_query_param_uint64 (&i64),
- TALER_PQ_query_param_amount (&d->coin_value),
- TALER_PQ_query_param_amount (&d->coin_fee), /* deposit fee */
- GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
- GNUNET_PQ_query_param_auto_from_type (&d->h_contract_terms),
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_transfer_to_coin_mapping",
- params);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'insert_transfer_to_coin_mapping' failed with status %d\n",
- qs);
- return qs;
- }
- if (0 == qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "'insert_transfer_to_coin_mapping' failed at %u: deposit
unknown\n",
- i);
- }
- }
- /* Update merchant_contract_terms 'wired' status: for all coins
- that were wired, set the respective order's "wired" status to
- true, *if* all other deposited coins associated with that order
- have also been wired (this time or earlier) */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Updating contract terms 'wired' status\n");
- for (unsigned int i = 0; i<td->details_length; i++)
- {
- const struct TALER_TrackTransferDetails *d = &td->details[i];
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_wired_by_coin_pub",
- params);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "'update_wired_by_coin_pub' failed with status %d\n",
- qs);
- return qs;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Committing transaction...\n");
- qs = postgres_commit (pg);
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
-}
-
-
-/**
- * Obtain information about wire fees charged by an exchange,
- * including signature (so we have proof).
- *
- * @param cls closure
- * @param master_pub public key of the exchange
- * @param wire_method the wire method
- * @param contract_date date of the contract to use for the lookup
- * @param[out] fees wire fees charged
- * @param[out] start_date start of fee being used
- * @param[out] end_date end of fee being used
- * @param[out] master_sig signature of exchange over fee structure
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_wire_fee (void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- const char *wire_method,
- struct GNUNET_TIME_Timestamp contract_date,
- struct TALER_WireFeeSet *fees,
- struct GNUNET_TIME_Timestamp *start_date,
- struct GNUNET_TIME_Timestamp *end_date,
- struct TALER_MasterSignatureP *master_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_HashCode h_wire_method;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (master_pub),
- GNUNET_PQ_query_param_auto_from_type (&h_wire_method),
- GNUNET_PQ_query_param_timestamp (&contract_date),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- &fees->wire),
- TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
- &fees->closing),
- GNUNET_PQ_result_spec_timestamp ("start_date",
- start_date),
- GNUNET_PQ_result_spec_timestamp ("end_date",
- end_date),
- GNUNET_PQ_result_spec_auto_from_type ("master_sig",
- master_sig),
- GNUNET_PQ_result_spec_end
- };
-
- check_connection (pg);
- GNUNET_CRYPTO_hash (wire_method,
- strlen (wire_method) + 1,
- &h_wire_method);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_wire_fee",
- params,
- rs);
-}
-
-
-/**
- * Closure for #lookup_deposits_by_contract_and_coin_cb().
- */
-struct LookupDepositsByCnCContext
-{
- /**
- * Function to call for each deposit.
- */
- TALER_MERCHANTDB_CoinDepositCallback cb;
+ /**
+ * Function to call for each order that was aggregated.
+ */
+ TALER_MERCHANTDB_TransferDetailsCallback cb;
/**
* Closure for @e cb.
@@ -3189,51 +2779,33 @@ struct LookupDepositsByCnCContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results.
*
- * @param cls of type `struct LookupDepositsByCnCContext *`
+ * @param cls of type `struct LookupTransferDetailsContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_deposits_by_contract_and_coin_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+lookup_transfer_details_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct LookupDepositsByCnCContext *ldcc = cls;
- struct PostgresClosure *pg = ldcc->pg;
+ struct LookupTransferDetailsContext *ltdc = cls;
+ struct PostgresClosure *pg = ltdc->pg;
for (unsigned int i = 0; i<num_results; i++)
{
- char *exchange_url;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
- struct TALER_Amount refund_fee;
- struct TALER_Amount wire_fee;
- struct TALER_MerchantWireHashP h_wire;
- struct GNUNET_TIME_Timestamp deposit_timestamp;
- struct GNUNET_TIME_Timestamp refund_deadline;
- struct TALER_ExchangeSignatureP exchange_sig;
- struct TALER_ExchangePublicKeyP exchange_pub;
+ uint64_t current_offset;
+ struct TALER_TrackTransferDetails ttd;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- 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_auto_from_type ("h_wire",
- &h_wire),
- GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
- &deposit_timestamp),
- GNUNET_PQ_result_spec_timestamp ("refund_deadline",
- &refund_deadline),
- 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_uint64 ("offset_in_exchange_list",
+ ¤t_offset),
+ GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+ &ttd.h_contract_terms),
+ GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+ &ttd.coin_pub),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+ &ttd.coin_value),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+ &ttd.coin_fee),
GNUNET_PQ_result_spec_end
};
@@ -3243,55 +2815,43 @@ lookup_deposits_by_contract_and_coin_cb (void *cls,
i))
{
GNUNET_break (0);
- ldcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- ldcc->cb (ldcc->cb_cls,
- exchange_url,
- &amount_with_fee,
- &deposit_fee,
- &refund_fee,
- &wire_fee,
- &h_wire,
- deposit_timestamp,
- refund_deadline,
- &exchange_sig,
- &exchange_pub);
+ ltdc->cb (ltdc->cb_cls,
+ (unsigned int) current_offset,
+ &ttd);
GNUNET_PQ_cleanup_result (rs);
}
- ldcc->qs = num_results;
+ ltdc->qs = num_results;
}
/**
- * Lookup information about coin payments by @a h_contract_terms and
- * @a coin_pub.
+ * Lookup transfer details.
*
* @param cls closure
- * @param instance_id instance to lookup payments for
- * @param h_contract_terms proposal data's hashcode
- * @param coin_pub public key to use for the search
- * @param cb function to call with payment data
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param cb function to call with detailed transfer data
* @param cb_cls closure for @a cb
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits_by_contract_and_coin (
+postgres_lookup_transfer_details (
void *cls,
- const char *instance_id,
- const struct TALER_PrivateContractHashP *h_contract_terms,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- TALER_MERCHANTDB_CoinDepositCallback cb,
+ const char *exchange_url,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ TALER_MERCHANTDB_TransferDetailsCallback cb,
void *cb_cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (wtid),
GNUNET_PQ_query_param_end
};
- struct LookupDepositsByCnCContext ldcc = {
+ struct LookupTransferDetailsContext ltdc = {
.cb = cb,
.cb_cls = cb_cls,
.pg = pg
@@ -3301,289 +2861,256 @@ postgres_lookup_deposits_by_contract_and_coin (
check_connection (pg);
qs = GNUNET_PQ_eval_prepared_multi_select (
pg->conn,
- "lookup_deposits_by_contract_and_coin",
+ "lookup_transfer_details",
params,
- &lookup_deposits_by_contract_and_coin_cb,
- &ldcc);
+ &lookup_transfer_details_cb,
+ <dc);
if (0 >= qs)
return qs;
- return ldcc.qs;
+ return ltdc.qs;
}
/**
- * Lookup transfer status.
+ * Store information about wire fees charged by an exchange,
+ * including signature (so we have proof).
*
* @param cls closure
- * @param instance_id at which instance should we resolve the transfer
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param[out] total_amount amount that was debited from our
- * aggregate balance at the exchange (in total, sum of
- * the wire transfer amount and the @a wire_fee)
- * @param[out] wire_fee the wire fee the exchange charged (only set if @a
have_exchange_sig is true)
- * @param[out] exchange_amount the amount the exchange claims was transferred
(only set if @a have_exchange_sig is true)
- * @param[out] execution_time when the transfer was executed by the exchange
(only set if @a have_exchange_sig is true)
- * @param[out] have_exchange_sig do we have a response from the exchange about
this transfer
- * @param[out] verified did we confirm the transfer was OK
- * @return transaction status
+ * @param master_pub public key of the exchange
+ * @param h_wire_method hash of wire method
+ * @param fees the fee charged
+ * @param start_date start of fee being used
+ * @param end_date end of fee being used
+ * @param master_sig signature of exchange over fee structure
+ * @return transaction status code
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer (
+postgres_store_wire_fee_by_exchange (
void *cls,
- const char *instance_id,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct TALER_Amount *total_amount,
- struct TALER_Amount *wire_fee,
- struct TALER_Amount *exchange_amount,
- struct GNUNET_TIME_Timestamp *execution_time,
- bool *have_exchange_sig,
- bool *verified)
+ const struct TALER_MasterPublicKeyP *master_pub,
+ const struct GNUNET_HashCode *h_wire_method,
+ const struct TALER_WireFeeSet *fees,
+ struct GNUNET_TIME_Timestamp start_date,
+ struct GNUNET_TIME_Timestamp end_date,
+ const struct TALER_MasterSignatureP *master_sig)
{
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_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (master_pub),
+ GNUNET_PQ_query_param_auto_from_type (h_wire_method),
+ TALER_PQ_query_param_amount (&fees->wire),
+ TALER_PQ_query_param_amount (&fees->closing),
+ GNUNET_PQ_query_param_timestamp (&start_date),
+ GNUNET_PQ_query_param_timestamp (&end_date),
+ GNUNET_PQ_query_param_auto_from_type (master_sig),
GNUNET_PQ_query_param_end
};
- uint8_t verified8;
- /** Amount we got actually credited, _excludes_ the wire fee */
- bool no_sig;
- struct TALER_Amount credit_amount;
- struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
- &credit_amount),
- GNUNET_PQ_result_spec_allow_null (
- TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
- wire_fee),
- &no_sig),
- GNUNET_PQ_result_spec_allow_null (
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_amount",
- exchange_amount),
- NULL),
- GNUNET_PQ_result_spec_allow_null (
- GNUNET_PQ_result_spec_timestamp ("execution_time",
- execution_time),
- NULL),
- GNUNET_PQ_result_spec_auto_from_type ("verified",
- &verified8),
- GNUNET_PQ_result_spec_end
- };
- enum GNUNET_DB_QueryStatus qs;
+ /* no preflight check here, run in its own transaction by the caller */
check_connection (pg);
- *execution_time = GNUNET_TIME_UNIT_ZERO_TS;
- qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "lookup_transfer",
- params,
- rs);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Lookup transfer returned %d\n",
- qs);
- if (qs > 0)
- {
- *have_exchange_sig = ! no_sig;
- *verified = (0 != verified8);
- if ( (! no_sig) &&
- (0 >
- TALER_amount_add (total_amount,
- &credit_amount,
- wire_fee)) )
- {
- GNUNET_break (0);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- }
- else
- {
- *verified = false;
- *have_exchange_sig = false;
- }
- return qs;
+ "Storing wire fee for %s starting at %s of %s\n",
+ TALER_B2S (master_pub),
+ GNUNET_TIME_timestamp2s (start_date),
+ TALER_amount2s (&fees->wire));
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_wire_fee",
+ params);
}
/**
- * Closure for #lookup_transfer_summary_cb().
+ * Add @a credit to a reserve to be used for tipping. Note that
+ * this function does not actually perform any wire transfers to
+ * credit the reserve, it merely tells the merchant backend that
+ * a reserve now exists. This has to happen before tips can be
+ * authorized.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param instance_id which instance is the reserve tied to
+ * @param reserve_priv which reserve is topped up or created
+ * @param reserve_pub which reserve is topped up or created
+ * @param master_pub master public key of the exchange
+ * @param exchange_url what URL is the exchange reachable at where the reserve
is located
+ * @param initial_balance how much money will be added to the reserve
+ * @param expiration when does the reserve expire?
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
*/
-struct LookupTransferSummaryContext
+static enum TALER_ErrorCode
+postgres_insert_reserve (void *cls,
+ const char *instance_id,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ const char *exchange_url,
+ const struct TALER_Amount *initial_balance,
+ struct GNUNET_TIME_Timestamp expiration)
{
- /**
- * Function to call for each order that was aggregated.
- */
- TALER_MERCHANTDB_TransferSummaryCallback cb;
-
- /**
- * Closure for @e cb.
- */
- void *cb_cls;
-
- /**
- * Plugin context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Transaction result.
- */
+ struct PostgresClosure *pg = cls;
+ unsigned int retries;
enum GNUNET_DB_QueryStatus qs;
-};
+ retries = 0;
+ check_connection (pg);
+RETRY:
+ if (MAX_RETRIES < ++retries)
+ return TALER_EC_GENERIC_DB_SOFT_FAILURE;
+ if (GNUNET_OK !=
+ postgres_start (pg,
+ "insert reserve"))
+ {
+ GNUNET_break (0);
+ return TALER_EC_GENERIC_DB_START_FAILED;
+ }
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupTransferSummaryContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_transfer_summary_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTransferSummaryContext *ltdc = cls;
- struct PostgresClosure *pg = ltdc->pg;
+ /* Setup reserve */
+ {
+ struct GNUNET_TIME_Timestamp now;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_timestamp (&now),
+ GNUNET_PQ_query_param_timestamp (&expiration),
+ TALER_PQ_query_param_amount (initial_balance),
+ GNUNET_PQ_query_param_end
+ };
- for (unsigned int i = 0; i<num_results; i++)
+ now = GNUNET_TIME_timestamp_get ();
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_reserve",
+ params);
+ if (0 > qs)
+ {
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return qs;
+ }
+ }
+ /* Store private key */
{
- char *order_id;
- struct TALER_Amount deposit_value;
- struct TALER_Amount deposit_fee;
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("order_id",
- &order_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
- &deposit_value),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
- &deposit_fee),
- GNUNET_PQ_result_spec_end
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_auto_from_type (reserve_priv),
+ GNUNET_PQ_query_param_string (exchange_url),
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_end
};
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_reserve_key",
+ params);
+ if (0 > qs)
{
- GNUNET_break (0);
- ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
+ postgres_rollback (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return qs;
}
- ltdc->cb (ltdc->cb_cls,
- order_id,
- &deposit_value,
- &deposit_fee);
- GNUNET_PQ_cleanup_result (rs);
}
- ltdc->qs = num_results;
+ qs = postgres_commit (pg);
+ if (0 <= qs)
+ return TALER_EC_NONE; /* success */
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto RETRY;
+ return qs;
}
/**
- * Lookup transfer summary.
+ * Confirms @a credit as the amount the exchange claims to have received and
+ * thus really 'activates' the reserve. This has to happen before tips can
+ * be authorized.
*
- * @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param cb function to call with detailed transfer data
- * @param cb_cls closure for @a cb
- * @return transaction status
+ * @param cls closure, typically a connection to the db
+ * @param instance_id which instance is the reserve tied to
+ * @param reserve_pub which reserve is topped up or created
+ * @param initial_exchange_balance how much money was be added to the reserve
+ * according to the exchange
+ * @return transaction status, usually
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_summary (
- void *cls,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MERCHANTDB_TransferSummaryCallback cb,
- void *cb_cls)
+postgres_activate_reserve (void *cls,
+ const char *instance_id,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_Amount *initial_exchange_balance)
{
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_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ TALER_PQ_query_param_amount (initial_exchange_balance),
GNUNET_PQ_query_param_end
};
- struct LookupTransferSummaryContext ltdc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
- enum GNUNET_DB_QueryStatus qs;
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_transfer_summary",
- params,
- &lookup_transfer_summary_cb,
- <dc);
- if (0 >= qs)
- return qs;
- return ltdc.qs;
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "activate_reserve",
+ params);
}
/**
- * Closure for #lookup_transfer_details_cb().
+ * Closure for #lookup_pending_reserves_cb.
*/
-struct LookupTransferDetailsContext
+struct LookupPendingReservesContext
{
/**
- * Function to call for each order that was aggregated.
+ * Postgres context.
*/
- TALER_MERCHANTDB_TransferDetailsCallback cb;
+ struct PostgresClosure *pg;
/**
- * Closure for @e cb.
+ * Function to call with the results
*/
- void *cb_cls;
+ TALER_MERCHANTDB_PendingReservesCallback cb;
/**
- * Plugin context.
+ * Closure for @e cb
*/
- struct PostgresClosure *pg;
+ void *cb_cls;
/**
- * Transaction result.
+ * Set in case of errors.
*/
enum GNUNET_DB_QueryStatus qs;
+
};
/**
* Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * that has returned @a num_results results about accounts.
*
- * @param cls of type `struct LookupTransferDetailsContext *`
+ * @param[in,out] cls of type `struct LookupReservesContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_transfer_details_cb (void *cls,
+lookup_pending_reserves_cb (void *cls,
PGresult *result,
unsigned int num_results)
{
- struct LookupTransferDetailsContext *ltdc = cls;
- struct PostgresClosure *pg = ltdc->pg;
+ struct LookupPendingReservesContext *lrc = cls;
+ struct PostgresClosure *pg = lrc->pg;
- for (unsigned int i = 0; i<num_results; i++)
+ for (unsigned int i = 0; i < num_results; i++)
{
- uint64_t current_offset;
- struct TALER_TrackTransferDetails ttd;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_Amount merchant_initial_balance;
+ char *exchange_url;
+ char *instance_id;
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("offset_in_exchange_list",
- ¤t_offset),
- GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
- &ttd.h_contract_terms),
- GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
- &ttd.coin_pub),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
- &ttd.coin_value),
- TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
- &ttd.coin_fee),
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ &reserve_pub),
+ GNUNET_PQ_result_spec_string ("merchant_id",
+ &instance_id),
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
+ &merchant_initial_balance),
GNUNET_PQ_result_spec_end
};
@@ -3593,247 +3120,59 @@ lookup_transfer_details_cb (void *cls,
i))
{
GNUNET_break (0);
- ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- ltdc->cb (ltdc->cb_cls,
- (unsigned int) current_offset,
- &ttd);
+ lrc->cb (lrc->cb_cls,
+ instance_id,
+ exchange_url,
+ &reserve_pub,
+ &merchant_initial_balance);
GNUNET_PQ_cleanup_result (rs);
}
- ltdc->qs = num_results;
}
/**
- * Lookup transfer details.
+ * Lookup reserves pending activation across all instances.
*
* @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param cb function to call with detailed transfer data
+ * @param cb function to call with reserve summary data
* @param cb_cls closure for @a cb
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_details (
- void *cls,
- const char *exchange_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_MERCHANTDB_TransferDetailsCallback cb,
- void *cb_cls)
+postgres_lookup_pending_reserves (void *cls,
+ TALER_MERCHANTDB_PendingReservesCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
+ struct LookupPendingReservesContext lrc = {
+ .pg = pg,
+ .cb = cb,
+ .cb_cls = cb_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_end
};
- struct LookupTransferDetailsContext ltdc = {
- .cb = cb,
- .cb_cls = cb_cls,
- .pg = pg
- };
enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (
- pg->conn,
- "lookup_transfer_details",
- params,
- &lookup_transfer_details_cb,
- <dc);
- if (0 >= qs)
- return qs;
- return ltdc.qs;
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_pending_reserves",
+ params,
+ &lookup_pending_reserves_cb,
+ &lrc);
+ if (lrc.qs < 0)
+ return lrc.qs;
+ return qs;
}
/**
- * Store information about wire fees charged by an exchange,
- * including signature (so we have proof).
- *
- * @param cls closure
- * @param master_pub public key of the exchange
- * @param h_wire_method hash of wire method
- * @param fees the fee charged
- * @param start_date start of fee being used
- * @param end_date end of fee being used
- * @param master_sig signature of exchange over fee structure
- * @return transaction status code
+ * Closure for #lookup_reserve_tips_cb().
*/
-static enum GNUNET_DB_QueryStatus
-postgres_store_wire_fee_by_exchange (
- void *cls,
- const struct TALER_MasterPublicKeyP *master_pub,
- const struct GNUNET_HashCode *h_wire_method,
- const struct TALER_WireFeeSet *fees,
- struct GNUNET_TIME_Timestamp start_date,
- struct GNUNET_TIME_Timestamp end_date,
- const struct TALER_MasterSignatureP *master_sig)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_auto_from_type (master_pub),
- GNUNET_PQ_query_param_auto_from_type (h_wire_method),
- TALER_PQ_query_param_amount (&fees->wire),
- TALER_PQ_query_param_amount (&fees->closing),
- GNUNET_PQ_query_param_timestamp (&start_date),
- GNUNET_PQ_query_param_timestamp (&end_date),
- GNUNET_PQ_query_param_auto_from_type (master_sig),
- GNUNET_PQ_query_param_end
- };
-
- /* 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 (master_pub),
- GNUNET_TIME_timestamp2s (start_date),
- TALER_amount2s (&fees->wire));
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_wire_fee",
- params);
-}
-
-
-/**
- * Add @a credit to a reserve to be used for tipping. Note that
- * this function does not actually perform any wire transfers to
- * credit the reserve, it merely tells the merchant backend that
- * a reserve now exists. This has to happen before tips can be
- * authorized.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_priv which reserve is topped up or created
- * @param reserve_pub which reserve is topped up or created
- * @param master_pub master public key of the exchange
- * @param exchange_url what URL is the exchange reachable at where the reserve
is located
- * @param initial_balance how much money will be added to the reserve
- * @param expiration when does the reserve expire?
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum TALER_ErrorCode
-postgres_insert_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePrivateKeyP *reserve_priv,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_MasterPublicKeyP *master_pub,
- const char *exchange_url,
- const struct TALER_Amount *initial_balance,
- struct GNUNET_TIME_Timestamp expiration)
-{
- struct PostgresClosure *pg = cls;
- unsigned int retries;
- enum GNUNET_DB_QueryStatus qs;
-
- retries = 0;
- check_connection (pg);
-RETRY:
- if (MAX_RETRIES < ++retries)
- return TALER_EC_GENERIC_DB_SOFT_FAILURE;
- if (GNUNET_OK !=
- postgres_start (pg,
- "insert reserve"))
- {
- GNUNET_break (0);
- return TALER_EC_GENERIC_DB_START_FAILED;
- }
-
- /* Setup reserve */
- {
- struct GNUNET_TIME_Timestamp now;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_timestamp (&now),
- GNUNET_PQ_query_param_timestamp (&expiration),
- TALER_PQ_query_param_amount (initial_balance),
- GNUNET_PQ_query_param_end
- };
-
- now = GNUNET_TIME_timestamp_get ();
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_reserve",
- params);
- if (0 > qs)
- {
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
- }
- }
- /* Store private key */
- {
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_auto_from_type (reserve_priv),
- GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- GNUNET_PQ_query_param_end
- };
-
- qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_reserve_key",
- params);
- if (0 > qs)
- {
- postgres_rollback (pg);
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
- }
- }
- qs = postgres_commit (pg);
- if (0 <= qs)
- return TALER_EC_NONE; /* success */
- if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
- goto RETRY;
- return qs;
-}
-
-
-/**
- * Confirms @a credit as the amount the exchange claims to have received and
- * thus really 'activates' the reserve. This has to happen before tips can
- * be authorized.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_pub which reserve is topped up or created
- * @param initial_exchange_balance how much money was be added to the reserve
- * according to the exchange
- * @return transaction status, usually
- * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_activate_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_Amount *initial_exchange_balance)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- TALER_PQ_query_param_amount (initial_exchange_balance),
- GNUNET_PQ_query_param_end
- };
-
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "activate_reserve",
- params);
-}
-
-
-/**
- * Closure for #lookup_pending_reserves_cb.
- */
-struct LookupPendingReservesContext
+struct LookupTipsContext
{
/**
* Postgres context.
@@ -3841,20 +3180,19 @@ struct LookupPendingReservesContext
struct PostgresClosure *pg;
/**
- * Function to call with the results
+ * Array with information about tips generated from this reserve.
*/
- TALER_MERCHANTDB_PendingReservesCallback cb;
+ struct TALER_MERCHANTDB_TipDetails *tips;
/**
- * Closure for @e cb
+ * Length of the @e tips array.
*/
- void *cb_cls;
+ unsigned int tips_length;
/**
* Set in case of errors.
*/
enum GNUNET_DB_QueryStatus qs;
-
};
@@ -3862,33 +3200,31 @@ struct LookupPendingReservesContext
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results about accounts.
*
- * @param[in,out] cls of type `struct LookupReservesContext *`
+ * @param[in,out] cls of type `struct LookupTipsContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
static void
-lookup_pending_reserves_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
+lookup_reserve_tips_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
{
- struct LookupPendingReservesContext *lrc = cls;
- struct PostgresClosure *pg = lrc->pg;
+ struct LookupTipsContext *ltc = cls;
+ struct PostgresClosure *pg = ltc->pg;
+ GNUNET_array_grow (ltc->tips,
+ ltc->tips_length,
+ num_results);
for (unsigned int i = 0; i < num_results; i++)
{
- struct TALER_ReservePublicKeyP reserve_pub;
- struct TALER_Amount merchant_initial_balance;
- char *exchange_url;
- char *instance_id;
+ struct TALER_MERCHANTDB_TipDetails *td = <c->tips[i];
struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
- &reserve_pub),
- GNUNET_PQ_result_spec_string ("merchant_id",
- &instance_id),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
- &merchant_initial_balance),
+ GNUNET_PQ_result_spec_string ("justification",
+ &td->reason),
+ GNUNET_PQ_result_spec_auto_from_type ("tip_id",
+ &td->tip_id),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+ &td->total_amount),
GNUNET_PQ_result_spec_end
};
@@ -3898,154 +3234,40 @@ lookup_pending_reserves_cb (void *cls,
i))
{
GNUNET_break (0);
- lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
return;
}
- lrc->cb (lrc->cb_cls,
- instance_id,
- exchange_url,
- &reserve_pub,
- &merchant_initial_balance);
- GNUNET_PQ_cleanup_result (rs);
}
}
/**
- * Lookup reserves pending activation across all instances.
+ * Lookup reserve details.
*
* @param cls closure
+ * @param instance_id instance to lookup payments for
+ * @param reserve_pub public key of the reserve to inspect
+ * @param fetch_tips if true, also return information about tips
* @param cb function to call with reserve summary data
* @param cb_cls closure for @a cb
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_lookup_pending_reserves (void *cls,
- TALER_MERCHANTDB_PendingReservesCallback cb,
- void *cb_cls)
+postgres_lookup_reserve (void *cls,
+ const char *instance_id,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ bool fetch_tips,
+ TALER_MERCHANTDB_ReserveDetailsCallback cb,
+ void *cb_cls)
{
struct PostgresClosure *pg = cls;
- struct LookupPendingReservesContext lrc = {
+ struct LookupTipsContext ltc = {
.pg = pg,
- .cb = cb,
- .cb_cls = cb_cls
+ .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
};
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_end
- };
- enum GNUNET_DB_QueryStatus qs;
-
- check_connection (pg);
- qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
- "lookup_pending_reserves",
- params,
- &lookup_pending_reserves_cb,
- &lrc);
- if (lrc.qs < 0)
- return lrc.qs;
- return qs;
-}
-
-
-/**
- * Closure for #lookup_reserve_tips_cb().
- */
-struct LookupTipsContext
-{
- /**
- * Postgres context.
- */
- struct PostgresClosure *pg;
-
- /**
- * Array with information about tips generated from this reserve.
- */
- struct TALER_MERCHANTDB_TipDetails *tips;
-
- /**
- * Length of the @e tips array.
- */
- unsigned int tips_length;
-
- /**
- * Set in case of errors.
- */
- enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupTipsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_reserve_tips_cb (void *cls,
- PGresult *result,
- unsigned int num_results)
-{
- struct LookupTipsContext *ltc = cls;
- struct PostgresClosure *pg = ltc->pg;
-
- GNUNET_array_grow (ltc->tips,
- ltc->tips_length,
- num_results);
- for (unsigned int i = 0; i < num_results; i++)
- {
- struct TALER_MERCHANTDB_TipDetails *td = <c->tips[i];
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_string ("justification",
- &td->reason),
- GNUNET_PQ_result_spec_auto_from_type ("tip_id",
- &td->tip_id),
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
- &td->total_amount),
- GNUNET_PQ_result_spec_end
- };
-
- if (GNUNET_OK !=
- GNUNET_PQ_extract_result (result,
- rs,
- i))
- {
- GNUNET_break (0);
- ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
- return;
- }
- }
-}
-
-
-/**
- * Lookup reserve details.
- *
- * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param reserve_pub public key of the reserve to inspect
- * @param fetch_tips if true, also return information about tips
- * @param cb function to call with reserve summary data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_reserve (void *cls,
- const char *instance_id,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- bool fetch_tips,
- TALER_MERCHANTDB_ReserveDetailsCallback cb,
- void *cb_cls)
-{
- struct PostgresClosure *pg = cls;
- struct LookupTipsContext ltc = {
- .pg = pg,
- .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
- };
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (instance_id),
- GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
GNUNET_PQ_query_param_end
};
struct GNUNET_TIME_Timestamp creation_time;
@@ -6206,980 +5428,6 @@ postgres_connect (void *cls)
struct GNUNET_PQ_PreparedStatement ps[] = {
GNUNET_PQ_make_prepare ("end_transaction",
"COMMIT"),
- /* for postgres_expire_locks() */
- GNUNET_PQ_make_prepare ("unlock_products",
- "DELETE FROM merchant_inventory_locks"
- " WHERE expiration < $1"),
- /* for postgres_expire_locks() */
- GNUNET_PQ_make_prepare ("unlock_orders",
- "DELETE FROM merchant_orders"
- " WHERE pay_deadline < $1"),
- /* for postgres_expire_locks() */
- GNUNET_PQ_make_prepare ("unlock_contracts",
- "DELETE FROM merchant_contract_terms"
- " WHERE NOT paid"
- " AND pay_deadline < $1"),
-
- /* for postgres_delete_order() */
- GNUNET_PQ_make_prepare ("delete_order",
- "WITH ms AS"
- "(SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- ", mc AS"
- "(SELECT paid"
- " FROM merchant_contract_terms"
- " JOIN ms USING (merchant_serial)"
- " WHERE order_id=$2) "
- "DELETE"
- " FROM merchant_orders mo"
- " WHERE order_id=$2"
- " AND merchant_serial=(SELECT merchant_serial
FROM ms)"
- " AND ( (pay_deadline < $3)"
- " OR (NOT EXISTS (SELECT paid FROM mc))"
- " OR ($4 AND (FALSE=(SELECT paid FROM mc)))
);"),
- GNUNET_PQ_make_prepare ("delete_contract",
- "DELETE"
- " FROM merchant_contract_terms"
- " WHERE order_id=$2 AND"
- " merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND NOT paid;"),
- /* for postgres_lookup_order() */
- GNUNET_PQ_make_prepare ("lookup_order",
- "SELECT"
- " contract_terms"
- ",claim_token"
- ",h_post_data"
- ",pos_key"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_orders.order_id=$2"),
- /* for postgres_lookup_order_summary() */
- GNUNET_PQ_make_prepare ("lookup_order_summary",
- "(SELECT"
- " creation_time"
- ",order_serial"
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_contract_terms.order_id=$2)"
- "UNION"
- "(SELECT"
- " creation_time"
- ",order_serial"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND merchant_orders.order_id=$2)"),
- /* for postgres_lookup_orders() */
- GNUNET_PQ_make_prepare ("lookup_orders_inc",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " CAST($6 as BOOL) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial > $3"
- " AND"
- " creation_time > $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial ASC"
- " LIMIT $2)"
- " ORDER BY order_serial ASC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($7 as BOOL)" /* otherwise $7 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($6 as BOOL)" /* otherwise $6 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- ",CAST($5 as BOOL)" /* otherwise $5 is unused and
Postgres unhappy */
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded_wired",
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_orders"
- " WHERE merchant_orders.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " NOT CAST($5 as BOOL)" /* unclaimed orders are
never paid */
- " AND"
- " NOT CAST($6 as BOOL)"/* unclaimed orders are
never refunded */
- " AND"
- " NOT CAST($7 as BOOL)" /* unclaimed orders are
never wired */
- " AND"
- " order_serial NOT IN"
- " (SELECT order_serial"
- " FROM merchant_contract_terms)" /* only
select unclaimed orders */
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- "UNION " /* union ensures elements are distinct! */
- "(SELECT"
- " order_id"
- ",order_serial"
- ",creation_time"
- " FROM merchant_contract_terms"
- " WHERE merchant_contract_terms.merchant_serial="
- " (SELECT merchant_serial "
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND"
- " order_serial < $3"
- " AND"
- " creation_time < $4"
- " AND"
- " BOOL($5) = paid"
- " AND"
- " BOOL($6) = (order_serial IN"
- " (SELECT order_serial "
- " FROM merchant_refunds))"
- " AND"
- " BOOL($7) = wired"
- " ORDER BY order_serial DESC"
- " LIMIT $2)"
- " ORDER BY order_serial DESC"
- " LIMIT $2"),
- /* for postgres_insert_order() */
- GNUNET_PQ_make_prepare ("insert_order",
- "INSERT INTO merchant_orders"
- "(merchant_serial"
- ",order_id"
- ",pay_deadline"
- ",claim_token"
- ",h_post_data"
- ",creation_time"
- ",contract_terms"
- ",pos_key"
- ",pos_algorithm)"
- " SELECT merchant_serial,"
- " $2, $3, $4, $5, $6, $7, $8, $9"
- " FROM merchant_instances"
- " WHERE merchant_id=$1"),
- /* for postgres_unlock_inventory() */
- GNUNET_PQ_make_prepare ("unlock_inventory",
- "DELETE"
- " FROM merchant_inventory_locks"
- " WHERE lock_uuid=$1"),
- /* for postgres_insert_order_lock() */
- GNUNET_PQ_make_prepare ("insert_order_lock",
- "WITH tmp AS"
- " (SELECT "
- " product_serial"
- " ,merchant_serial"
- " ,total_stock"
- " ,total_sold"
- " ,total_lost"
- " FROM merchant_inventory"
- " WHERE product_id=$3"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1))"
- " INSERT INTO merchant_order_locks"
- " (product_serial"
- " ,total_locked"
- " ,order_serial)"
- " SELECT tmp.product_serial, $4, order_serial"
- " FROM merchant_orders"
- " JOIN tmp USING(merchant_serial)"
- " WHERE order_id=$2 AND"
- " tmp.total_stock - tmp.total_sold -
tmp.total_lost - $4 >= "
- " (SELECT COALESCE(SUM(total_locked), 0)"
- " FROM merchant_inventory_locks"
- " WHERE product_serial=tmp.product_serial)
+ "
- " (SELECT COALESCE(SUM(total_locked), 0)"
- " FROM merchant_order_locks"
- " WHERE
product_serial=tmp.product_serial)"),
- /* for postgres_lookup_contract_terms() */
- GNUNET_PQ_make_prepare ("lookup_contract_terms",
- "SELECT"
- " contract_terms"
- ",order_serial"
- ",claim_token"
- ",paid"
- " FROM merchant_contract_terms"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_lookup_contract_terms() */
- GNUNET_PQ_make_prepare ("lookup_contract_terms2",
- "SELECT"
- " contract_terms"
- ",order_serial"
- ",claim_token"
- ",paid"
- ",pos_key"
- ",pos_algorithm"
- " FROM merchant_contract_terms"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_insert_contract_terms() */
- GNUNET_PQ_make_prepare ("insert_contract_terms",
- "INSERT INTO merchant_contract_terms"
- "(order_serial"
- ",merchant_serial"
- ",order_id"
- ",contract_terms"
- ",h_contract_terms"
- ",creation_time"
- ",pay_deadline"
- ",refund_deadline"
- ",fulfillment_url"
- ",claim_token"
- ",pos_key"
- ",pos_algorithm)"
- "SELECT"
- " mo.order_serial"
- ",mo.merchant_serial"
- ",mo.order_id"
- ",$3" /* contract_terms */
- ",$4" /* h_contract_terms */
- ",mo.creation_time"
- ",$5" /* pay_deadline */
- ",$6" /* refund_deadline */
- ",$7" /* fulfillment_url */
- ",mo.claim_token"
- ",mo.pos_key"
- ",mo.pos_algorithm"
- " FROM merchant_orders mo"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " RETURNING order_serial"),
- /* for postgres_update_contract_terms() */
- GNUNET_PQ_make_prepare ("update_contract_terms",
- "UPDATE merchant_contract_terms SET"
- " contract_terms=$3"
- ",h_contract_terms=$4"
- ",pay_deadline=$5"
- ",refund_deadline=$6"
- ",fulfillment_url=$7"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"),
- /* for postgres_delete_contract_terms() */
- GNUNET_PQ_make_prepare ("delete_contract_terms",
- "DELETE FROM merchant_contract_terms"
- " WHERE order_id=$2"
- " AND merchant_serial="
- " (SELECT merchant_serial"
- " FROM merchant_instances"
- " WHERE merchant_id=$1)"
- " AND ( ( (pay_deadline < $4) AND"
- " (NOT paid) ) OR"
- " (creation_time + $3 < $4) )"),
/* for postgres_lookup_deposits() */
GNUNET_PQ_make_prepare ("lookup_deposits",
"SELECT"
@@ -8426,19 +6674,32 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_update_product;
plugin->lock_product
= &TMH_PG_lock_product;
- plugin->expire_locks = &postgres_expire_locks;
- plugin->delete_order = &postgres_delete_order;
- plugin->lookup_order = &postgres_lookup_order;
- plugin->lookup_order_summary = &postgres_lookup_order_summary;
- plugin->lookup_orders = &postgres_lookup_orders;
- plugin->insert_order = &postgres_insert_order;
- plugin->unlock_inventory = &postgres_unlock_inventory;
- plugin->insert_order_lock = &postgres_insert_order_lock;
- plugin->lookup_contract_terms = &postgres_lookup_contract_terms;
- plugin->lookup_contract_terms2 = &postgres_lookup_contract_terms2;
- plugin->insert_contract_terms = &postgres_insert_contract_terms;
- plugin->update_contract_terms = &postgres_update_contract_terms;
- plugin->delete_contract_terms = &postgres_delete_contract_terms;
+ plugin->expire_locks
+ = &TMH_PG_expire_locks;
+ plugin->delete_order
+ = &TMH_PG_delete_order;
+ plugin->lookup_order
+ = &TMH_PG_lookup_order;
+ plugin->lookup_order_summary
+ = &TMH_PG_lookup_order_summary;
+ plugin->lookup_orders
+ = &TMH_PG_lookup_orders;
+ plugin->insert_order
+ = &TMH_PG_insert_order;
+ plugin->unlock_inventory
+ = &TMH_PG_unlock_inventory;
+ plugin->insert_order_lock
+ = &TMH_PG_insert_order_lock;
+ plugin->lookup_contract_terms
+ = &TMH_PG_lookup_contract_terms;
+ plugin->lookup_contract_terms2
+ = &TMH_PG_lookup_contract_terms2;
+ plugin->insert_contract_terms
+ = &TMH_PG_insert_contract_terms;
+ plugin->update_contract_terms
+ = &TMH_PG_update_contract_terms;
+ plugin->delete_contract_terms
+ = &TMH_PG_delete_contract_terms;
plugin->lookup_deposits = &postgres_lookup_deposits;
plugin->insert_exchange_signkey = &postgres_insert_exchange_signkey;
plugin->insert_deposit = &postgres_insert_deposit;
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-merchant] branch master updated: Factor out 13 new functions (shit job),
gnunet <=