aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-07-31 23:39:55 +0200
committerChristian Grothoff <christian@grothoff.org>2024-07-31 23:39:55 +0200
commitc10874a858745b4205feabb38ed8f5e8bd11acc1 (patch)
tree1aa235f8e543ec5e2055bd6ac8b521b44b3840c2
parent854bad7d7c220c9ea9f4d61eb8fd46548a160da2 (diff)
fix account_kyc_set_status
-rw-r--r--src/backend/taler-merchant-depositcheck.c63
-rw-r--r--src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c218
-rw-r--r--src/backenddb/merchant-0010.sql14
-rw-r--r--src/backenddb/pg_account_kyc_set_status.c85
-rw-r--r--src/backenddb/pg_account_kyc_set_status.h12
-rw-r--r--src/backenddb/pg_account_kyc_set_status.sql116
-rw-r--r--src/backenddb/procedures.sql.in1
-rw-r--r--src/backenddb/test_merchantdb.c18
-rw-r--r--src/include/taler_merchantdb_plugin.h54
9 files changed, 449 insertions, 132 deletions
diff --git a/src/backend/taler-merchant-depositcheck.c b/src/backend/taler-merchant-depositcheck.c
index cd0242f0..ff90c505 100644
--- a/src/backend/taler-merchant-depositcheck.c
+++ b/src/backend/taler-merchant-depositcheck.c
@@ -407,8 +407,9 @@ run_at (struct GNUNET_TIME_Absolute deadline)
* @param dr HTTP response data
*/
static void
-deposit_get_cb (void *cls,
- const struct TALER_EXCHANGE_GetDepositResponse *dr)
+deposit_get_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_GetDepositResponse *dr)
{
struct ExchangeInteraction *w = cls;
struct GNUNET_TIME_Absolute future_retry;
@@ -425,9 +426,10 @@ deposit_get_cb (void *cls,
"Exchange returned wire transfer over %s for deposited coin %s\n",
TALER_amount2s (&dr->details.ok.coin_contribution),
TALER_B2S (&w->coin_pub));
- qs = db_plugin->insert_deposit_to_transfer (db_plugin->cls,
- w->deposit_serial,
- &dr->details.ok);
+ qs = db_plugin->insert_deposit_to_transfer (
+ db_plugin->cls,
+ w->deposit_serial,
+ &dr->details.ok);
if (qs < 0)
{
GNUNET_break (0);
@@ -468,6 +470,12 @@ deposit_get_cb (void *cls,
exchange_url,
dr->details.accepted.requirement_row,
now,
+ MHD_HTTP_ACCEPTED,
+ TALER_EC_NONE,
+ NULL,
+ 0,
+ NULL,
+ false,
dr->details.accepted.kyc_ok);
if (qs < 0)
{
@@ -598,7 +606,8 @@ pending_deposits_cb (
const struct TALER_Amount *deposit_fee,
const struct TALER_CoinSpendPublicKeyP *coin_pub)
{
- struct ExchangeInteraction *w = GNUNET_new (struct ExchangeInteraction);
+ struct ExchangeInteraction *w
+ = GNUNET_new (struct ExchangeInteraction);
(void) cls;
if (GNUNET_TIME_absolute_is_future (wire_deadline))
@@ -624,7 +633,8 @@ pending_deposits_cb (
w);
w_count++;
GNUNET_assert (NULL != keys);
- if (GNUNET_TIME_absolute_is_past (keys->key_data_expiration.abs_time))
+ if (GNUNET_TIME_absolute_is_past (
+ keys->key_data_expiration.abs_time))
{
/* Parent should re-start us, then we will re-fetch /keys */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -693,7 +703,8 @@ select_work (void *cls)
GNUNET_break (0);
return;
}
- if (GNUNET_TIME_absolute_is_past (keys->key_data_expiration.abs_time))
+ if (GNUNET_TIME_absolute_is_past (
+ keys->key_data_expiration.abs_time))
{
/* Parent should re-start us, then we will re-fetch /keys */
GNUNET_SCHEDULER_shutdown ();
@@ -706,12 +717,13 @@ select_work (void *cls)
db_plugin->preflight (db_plugin->cls);
if (retry)
limit = 1;
- qs = db_plugin->lookup_pending_deposits (db_plugin->cls,
- exchange_url,
- limit,
- retry,
- &pending_deposits_cb,
- NULL);
+ qs = db_plugin->lookup_pending_deposits (
+ db_plugin->cls,
+ exchange_url,
+ limit,
+ retry,
+ &pending_deposits_cb,
+ NULL);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Looking up pending deposits query status was %d\n",
(int) qs);
@@ -792,17 +804,18 @@ start_worker (const char *base_url)
"Launching worker for exchange `%s' using `%s`\n",
base_url,
cfg_filename);
- return GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL,
- NULL,
- NULL,
- "taler-merchant-depositcheck",
- "taler-merchant-depositcheck",
- "-c", cfg_filename,
- "-e", base_url,
- "-L", "INFO",
- test_mode ? "-t" : NULL,
- NULL);
+ return GNUNET_OS_start_process (
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL,
+ NULL,
+ NULL,
+ "taler-merchant-depositcheck",
+ "taler-merchant-depositcheck",
+ "-c", cfg_filename,
+ "-e", base_url,
+ "-L", "INFO",
+ test_mode ? "-t" : NULL,
+ NULL);
}
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
index 3cf4b161..9c215872 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
@@ -475,6 +475,78 @@ ekr_finished (struct ExchangeKycRequest *ekr)
/**
+ * Store KYC response from the exchange in the
+ * local database.
+ *
+ * @param ekr request context
+ * @param ks HTTP response details
+ * @param aks account KYC status details
+ * @return true if the operation was successful
+ */
+static bool
+store_kyc_status (
+ const struct ExchangeKycRequest *ekr,
+ const struct TALER_EXCHANGE_KycStatus *ks,
+ const struct TALER_EXCHANGE_AccountKycStatus *aks)
+{
+ unsigned int dl_cnt = 0;
+
+ for (unsigned int i = 0; i<aks->limits_length; i++)
+ {
+ const struct TALER_EXCHANGE_AccountLimit *limit
+ = &aks->limits[i];
+
+ if (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT ==
+ limit->operation_type)
+ dl_cnt++;
+ }
+
+ {
+ struct TALER_MERCHANTDB_DepositLimits dls[GNUNET_NZL (dl_cnt)];
+ enum GNUNET_DB_QueryStatus qs;
+ unsigned int off = 0;
+
+ for (unsigned int i = 0; i<aks->limits_length; i++)
+ {
+ const struct TALER_EXCHANGE_AccountLimit *limit
+ = &aks->limits[i];
+ struct TALER_MERCHANTDB_DepositLimits *dl
+ = &dls[off];
+
+ if (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT !=
+ limit->operation_type)
+ continue;
+ dl->timeframe = limit->timeframe;
+ dl->threshold = limit->threshold;
+ dl->soft_limit = limit->soft_limit;
+ off++;
+ }
+ qs = TMH_db->account_kyc_set_status (
+ TMH_db->cls,
+ ekr->kc->mi->settings.id,
+ &ekr->h_wire,
+ ekr->exchange_url,
+ ekr->exchange_kyc_serial,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ &aks->access_token,
+ dl_cnt,
+ dls,
+ aks->aml_review,
+ false);
+ if (qs < 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to store KYC status in database!\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/**
* Function called with the result of a KYC check.
*
* @param cls a `struct ExchangeKycRequest *`
@@ -493,44 +565,35 @@ exchange_check_cb (
{
case MHD_HTTP_OK:
{
- enum GNUNET_DB_QueryStatus qs;
const struct TALER_EXCHANGE_AccountKycStatus *aks;
aks = &ks->details.ok;
- // FIXME: also store aks->access_token, limits,
- // aml_review, etc.!
- qs = TMH_db->account_kyc_set_status (
- TMH_db->cls,
- kc->mi->settings.id,
- &ekr->h_wire,
- ekr->exchange_url,
- ekr->exchange_kyc_serial,
- GNUNET_TIME_timestamp_get (),
- true);
- if (qs < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to store KYC status in database!\n");
- }
+ GNUNET_break (store_kyc_status (ekr,
+ ks,
+ aks));
}
break;
case MHD_HTTP_ACCEPTED:
{
- struct GNUNET_TIME_Timestamp now;
- enum GNUNET_DB_QueryStatus qs;
- const struct TALER_EXCHANGE_AccountKycStatus *aks;
+ const struct TALER_EXCHANGE_AccountKycStatus *aks
+ = &ks->details.accepted;
char *kyc_url;
- char *ats;
-
- aks = &ks->details.accepted;
- ats = GNUNET_STRINGS_data_to_string_alloc (
- &aks->access_token,
- sizeof (aks->access_token));
- GNUNET_asprintf (&kyc_url,
- "%s/kyc-spa/%s",
- ekr->exchange_url,
- ats);
- GNUNET_free (ats);
+
+ GNUNET_break (store_kyc_status (ekr,
+ ks,
+ aks));
+ {
+ char *ats;
+
+ ats = GNUNET_STRINGS_data_to_string_alloc (
+ &aks->access_token,
+ sizeof (aks->access_token));
+ GNUNET_asprintf (&kyc_url,
+ "%s/kyc-spa/%s",
+ ekr->exchange_url,
+ ats);
+ GNUNET_free (ats);
+ }
GNUNET_assert (
0 ==
json_array_append_new (
@@ -545,37 +608,25 @@ exchange_check_cb (
GNUNET_JSON_pack_string ("payto_uri",
ekr->payto_uri))));
GNUNET_free (kyc_url);
- now = GNUNET_TIME_timestamp_get ();
- // FIXME: also store aks->access_token, limits,
- // aml_review, etc.!
- qs = TMH_db->account_kyc_set_status (
- TMH_db->cls,
- kc->mi->settings.id,
- &ekr->h_wire,
- ekr->exchange_url,
- ekr->exchange_kyc_serial,
- now,
- false);
- if (qs < 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to store KYC status in database!\n");
- }
break;
}
case MHD_HTTP_NO_CONTENT:
{
- struct GNUNET_TIME_Timestamp now;
enum GNUNET_DB_QueryStatus qs;
- now = GNUNET_TIME_timestamp_get ();
qs = TMH_db->account_kyc_set_status (
TMH_db->cls,
kc->mi->settings.id,
&ekr->h_wire,
ekr->exchange_url,
ekr->exchange_kyc_serial,
- now,
+ GNUNET_TIME_timestamp_get (),
+ MHD_HTTP_NO_CONTENT,
+ TALER_EC_NONE,
+ NULL,
+ 0,
+ NULL,
+ false,
true);
if (qs < 0)
{
@@ -587,9 +638,8 @@ exchange_check_cb (
case MHD_HTTP_FORBIDDEN:
case MHD_HTTP_NOT_FOUND:
case MHD_HTTP_CONFLICT:
- case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: // FIXME: real?
{
- struct GNUNET_TIME_Timestamp now;
enum GNUNET_DB_QueryStatus qs;
GNUNET_assert (
@@ -605,15 +655,19 @@ exchange_check_cb (
ks->hr.http_status),
GNUNET_JSON_pack_string ("payto_uri",
ekr->payto_uri))));
- now = GNUNET_TIME_timestamp_get ();
- // FIXME: also store HTTP status code + EC in DB!
qs = TMH_db->account_kyc_set_status (
TMH_db->cls,
kc->mi->settings.id,
&ekr->h_wire,
ekr->exchange_url,
ekr->exchange_kyc_serial,
- now,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ NULL,
+ 0,
+ NULL,
+ false,
true);
if (qs < 0)
{
@@ -623,22 +677,46 @@ exchange_check_cb (
}
break;
default:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
- ks->hr.http_status,
- ks->hr.ec);
- kc->response_code = MHD_HTTP_BAD_GATEWAY;
- GNUNET_assert (
- 0 ==
- json_array_append_new (
- kc->timeout_kycs,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("exchange_url",
- ekr->exchange_url),
- GNUNET_JSON_pack_uint64 ("exchange_code",
- ks->hr.ec),
- GNUNET_JSON_pack_uint64 ("exchange_http_status",
- ks->hr.http_status))));
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
+ ks->hr.http_status,
+ ks->hr.ec);
+ kc->response_code = MHD_HTTP_BAD_GATEWAY;
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ kc->timeout_kycs,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("exchange_url",
+ ekr->exchange_url),
+ GNUNET_JSON_pack_uint64 ("exchange_code",
+ ks->hr.ec),
+ GNUNET_JSON_pack_uint64 ("exchange_http_status",
+ ks->hr.http_status))));
+ qs = TMH_db->account_kyc_set_status (
+ TMH_db->cls,
+ kc->mi->settings.id,
+ &ekr->h_wire,
+ ekr->exchange_url,
+ ekr->exchange_kyc_serial,
+ GNUNET_TIME_timestamp_get (),
+ ks->hr.http_status,
+ ks->hr.ec,
+ NULL,
+ 0,
+ NULL,
+ false,
+ true);
+ if (qs < 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to store KYC status in database!\n");
+ }
+ break;
+ }
}
ekr_finished (ekr);
}
diff --git a/src/backenddb/merchant-0010.sql b/src/backenddb/merchant-0010.sql
index 7f3504e9..e2839aa4 100644
--- a/src/backenddb/merchant-0010.sql
+++ b/src/backenddb/merchant-0010.sql
@@ -30,13 +30,13 @@ ALTER TABLE merchant_kyc
DROP COLUMN aml_decision
,DROP COLUMN exchange_sig
,DROP COLUMN exchange_pub
- ,ADD COLUMN access_token BLOB DEFAULT NULL
+ ,ADD COLUMN access_token BYTEA DEFAULT NULL
,ADD COLUMN exchange_http_status INT4 DEFAULT(0)
,ADD COLUMN exchange_ec_code INT4 DEFAULT(0)
,ADD COLUMN aml_review BOOL DEFAULT(FALSE)
- ,ADD COLUMN deposit_threshold taler_amount_currency[] DEFAULT NULL
- ,ADD COLUMN deposit_timeframe INT8[] DEFAULT NULL
- ,ADD COLUMN deposit_limit_is_soft BOOL[] DEFAULT NULL
+ ,ADD COLUMN deposit_thresholds taler_amount_currency[] DEFAULT NULL
+ ,ADD COLUMN deposit_timeframes INT8[] DEFAULT NULL
+ ,ADD COLUMN deposit_limits_are_soft BOOL[] DEFAULT NULL
,ADD CONSTRAINT access_token_length_check CHECK (LENGTH(access_token) = 32);
COMMENT ON COLUMN merchant_kyc.access_token
@@ -47,11 +47,11 @@ COMMENT ON COLUMN merchant_kyc.exchange_ec_code
IS 'Last Taler error code returned by the exchange when inquiring about our KYC status.';
COMMENT ON COLUMN merchant_kyc.aml_review
IS 'True if our account is under AML review according to the exchange.';
-COMMENT ON COLUMN merchant_kyc.deposit_threshold
+COMMENT ON COLUMN merchant_kyc.deposit_thresholds
IS 'Maximum amount we are allowed to deposit in a given timeframe under current rules.';
-COMMENT ON COLUMN merchant_kyc.deposit_timeframe
+COMMENT ON COLUMN merchant_kyc.deposit_timeframes
IS 'Timeframe for which the deposit_threshold applies.';
-COMMENT ON COLUMN merchant_kyc.deposit_limit_is_soft
+COMMENT ON COLUMN merchant_kyc.deposit_limits_are_soft
IS 'True if this is a soft limit';
diff --git a/src/backenddb/pg_account_kyc_set_status.c b/src/backenddb/pg_account_kyc_set_status.c
index 444b263c..68835414 100644
--- a/src/backenddb/pg_account_kyc_set_status.c
+++ b/src/backenddb/pg_account_kyc_set_status.c
@@ -25,6 +25,7 @@
#include "pg_account_kyc_set_status.h"
#include "pg_helper.h"
+
enum GNUNET_DB_QueryStatus
TMH_PG_account_kyc_set_status (
void *cls,
@@ -33,39 +34,81 @@ TMH_PG_account_kyc_set_status (
const char *exchange_url,
uint64_t exchange_kyc_serial,
struct GNUNET_TIME_Timestamp timestamp,
+ unsigned int exchange_http_status,
+ enum TALER_ErrorCode exchange_ec_code,
+ const struct TALER_AccountAccessTokenP *access_token,
+ unsigned int num_limits,
+ const struct TALER_MERCHANTDB_DepositLimits *limits,
+ bool in_aml_review,
bool kyc_ok)
{
struct PostgresClosure *pg = cls;
+ uint32_t http_status32 = (uint32_t) exchange_http_status;
+ uint32_t ec_code32 = (uint32_t) exchange_ec_code;
+ struct TALER_Amount thresholds[GNUNET_NZL (num_limits)];
+ struct GNUNET_TIME_Relative timeframes[GNUNET_NZL (num_limits)];
+ bool soft_limits[GNUNET_NZL (num_limits)];
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_string (merchant_id),
GNUNET_PQ_query_param_auto_from_type (h_wire),
GNUNET_PQ_query_param_string (exchange_url),
- GNUNET_PQ_query_param_uint64 (&exchange_kyc_serial),
GNUNET_PQ_query_param_timestamp (&timestamp),
+ GNUNET_PQ_query_param_uint64 (&exchange_kyc_serial),
+ GNUNET_PQ_query_param_uint32 (&http_status32),
+ GNUNET_PQ_query_param_uint32 (&ec_code32),
+ NULL != access_token
+ ? GNUNET_PQ_query_param_auto_from_type (access_token)
+ : GNUNET_PQ_query_param_null (),
+ TALER_PQ_query_param_array_amount (num_limits,
+ thresholds,
+ pg->conn),
+ GNUNET_PQ_query_param_array_rel_time (num_limits,
+ timeframes,
+ pg->conn),
+ GNUNET_PQ_query_param_array_bool (num_limits,
+ soft_limits,
+ pg->conn),
+ GNUNET_PQ_query_param_bool (in_aml_review),
GNUNET_PQ_query_param_bool (kyc_ok),
GNUNET_PQ_query_param_end
};
+ bool no_instance;
+ bool no_account;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_bool ("no_instance",
+ &no_instance),
+ GNUNET_PQ_result_spec_bool ("no_account",
+ &no_account),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
check_connection (pg);
PREPARE (pg,
- "upsert_account_kyc",
- "INSERT INTO merchant_kyc"
- "(kyc_timestamp"
- ",kyc_ok"
- ",exchange_kyc_serial"
- ",account_serial"
- ",exchange_url)"
- " SELECT $5, $6, $4, account_serial, $3"
- " FROM merchant_instances"
- " JOIN merchant_accounts USING (merchant_serial)"
- " WHERE merchant_id=$1"
- " AND h_wire=$2"
- " ON CONFLICT(account_serial,exchange_url) DO "
- "UPDATE"
- " SET exchange_kyc_serial=$4"
- " ,kyc_timestamp=$5"
- " ,kyc_ok=$6");
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "upsert_account_kyc",
- params);
+ "account_kyc_set_status",
+ "SELECT "
+ " out_no_instance AS no_instance"
+ " ,out_no_account AS no_account"
+ " FROM merchant_do_account_kyc_set_status"
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);");
+ for (unsigned int i=0; i<num_limits; i++)
+ {
+ const struct TALER_MERCHANTDB_DepositLimits *limit
+ = &limits[i];
+
+ thresholds[i] = limit->threshold;
+ timeframes[i] = limit->timeframe;
+ soft_limits[i] = limit->soft_limit;
+ }
+ qs = GNUNET_PQ_eval_prepared_singleton_select (
+ pg->conn,
+ "account_kyc_set_status",
+ params,
+ rs);
+ GNUNET_PQ_cleanup_query_params_closures (params);
+ if (qs <= 0)
+ return qs;
+ GNUNET_break (! no_instance);
+ GNUNET_break (! no_account);
+ return qs;
}
diff --git a/src/backenddb/pg_account_kyc_set_status.h b/src/backenddb/pg_account_kyc_set_status.h
index 84abe48a..cc1f85b5 100644
--- a/src/backenddb/pg_account_kyc_set_status.h
+++ b/src/backenddb/pg_account_kyc_set_status.h
@@ -34,6 +34,12 @@
* @param exchange_url base URL of the exchange to check
* @param exchange_kyc_serial serial number for our account at the exchange (0 if unknown)
* @param timestamp timestamp to store
+ * @param exchange_http_status HTTP status code returned last by the exchange
+ * @param exchange_ec_code Taler error code returned last by the exchange
+ * @param access_token access token for the KYC process, NULL for none
+ * @param num_limits length of the @a limits array
+ * @param limits array with deposit limits returned by the exchange
+ * @param in_aml_review true if the exchange says the account is under review
* @param kyc_ok current KYC status (true for satisfied)
* @return database result code
*/
@@ -45,6 +51,12 @@ TMH_PG_account_kyc_set_status (
const char *exchange_url,
uint64_t exchange_kyc_serial,
struct GNUNET_TIME_Timestamp timestamp,
+ unsigned int exchage_http_status,
+ enum TALER_ErrorCode exchange_ec_code,
+ const struct TALER_AccountAccessTokenP *access_token,
+ unsigned int num_limits,
+ const struct TALER_MERCHANTDB_DepositLimits *limits,
+ bool in_aml_review,
bool kyc_ok);
#endif
diff --git a/src/backenddb/pg_account_kyc_set_status.sql b/src/backenddb/pg_account_kyc_set_status.sql
new file mode 100644
index 00000000..f72ab6ec
--- /dev/null
+++ b/src/backenddb/pg_account_kyc_set_status.sql
@@ -0,0 +1,116 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2024 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/>
+--
+
+
+CREATE OR REPLACE FUNCTION merchant_do_account_kyc_set_status (
+ IN in_merchant_id TEXT,
+ IN in_h_wire BYTEA,
+ IN in_exchange_url TEXT,
+ IN in_timestamp INT8,
+ IN in_exchange_kyc_serial INT8,
+ IN in_exchange_http_status INT4,
+ IN in_exchange_ec_code INT4,
+ IN in_access_token BYTEA,
+ IN ina_thresholds taler_amount_currency[],
+ IN ina_timeframes INT8[],
+ IN ina_soft_limits BOOL[],
+ IN in_aml_active BOOL,
+ IN in_kyc_ok BOOL,
+ OUT out_no_instance BOOL,
+ OUT out_no_account BOOL)
+LANGUAGE plpgsql
+AS $$
+DECLARE
+ my_merchant_id INT8;
+ my_account_serial INT8;
+ ini_cat INT8;
+ rec RECORD;
+BEGIN
+
+out_no_instance=FALSE;
+out_no_account=FALSE;
+
+-- Which instance are we using?
+SELECT merchant_serial
+ INTO my_merchant_id
+ FROM merchant_instances
+ WHERE merchant_id=in_merchant_id;
+
+IF NOT FOUND
+THEN
+ out_no_instance=TRUE;
+ RETURN;
+END IF;
+
+SELECT account_serial
+ INTO my_account_serial
+ FROM merchant_accounts
+ WHERE merchant_serial=my_merchant_id
+ AND h_wire=in_h_wire;
+
+IF NOT FOUND
+THEN
+ out_no_account=TRUE;
+ RETURN;
+END IF;
+
+INSERT INTO merchant_kyc
+ (kyc_timestamp
+ ,kyc_ok
+ ,exchange_kyc_serial
+ ,account_serial
+ ,exchange_url
+ ,deposit_thresholds
+ ,deposit_timeframes
+ ,deposit_limits_are_soft
+ ,aml_review
+ ,exchange_http_status
+ ,exchange_ec_code
+ ,access_token)
+VALUES
+ (in_timestamp
+ ,in_kyc_ok
+ ,in_exchange_kyc_serial
+ ,my_account_serial
+ ,in_exchange_url
+ ,ina_thresholds
+ ,ina_timeframes
+ ,ina_soft_limits
+ ,in_aml_active
+ ,in_exchange_http_status
+ ,in_exchange_ec_code
+ ,in_access_token)
+ ON CONFLICT DO NOTHING;
+
+IF NOT FOUND
+THEN
+ UPDATE merchant_kyc
+ SET exchange_kyc_serial=in_exchange_kyc_serial
+ ,kyc_timestamp=in_timestamp
+ ,kyc_ok=in_kyc_ok
+ ,deposit_thresholds=ina_thresholds
+ ,deposit_timeframes=ina_timeframes
+ ,deposit_limits_are_soft=ina_soft_limits
+ ,aml_review=in_aml_active
+ ,exchange_http_status=in_exchange_http_status
+ ,exchange_ec_code=in_exchange_ec_code
+ ,access_token=in_access_token
+ WHERE account_serial=my_account_serial
+ AND exchange_url=in_exchange_url;
+END IF;
+
+-- Success!
+END $$;
diff --git a/src/backenddb/procedures.sql.in b/src/backenddb/procedures.sql.in
index 9afa246b..bdf41934 100644
--- a/src/backenddb/procedures.sql.in
+++ b/src/backenddb/procedures.sql.in
@@ -22,5 +22,6 @@ SET search_path TO merchant;
#include "pg_insert_product.sql"
#include "pg_insert_transfer_details.sql"
#include "pg_update_product.sql"
+#include "pg_account_kyc_set_status.sql"
COMMIT;
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 5f8b5eb7..c2028261 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -5626,6 +5626,12 @@ test_kyc (void)
"https://exchange.net/",
1LLU,
now,
+ MHD_HTTP_OK,
+ TALER_EC_NONE,
+ NULL,
+ 0,
+ NULL,
+ false,
false));
TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->account_kyc_set_status (plugin->cls,
@@ -5634,6 +5640,12 @@ test_kyc (void)
"https://exchange2.com/",
1LLU,
now,
+ MHD_HTTP_OK,
+ TALER_EC_NONE,
+ NULL,
+ 0,
+ NULL,
+ false,
false));
TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->account_kyc_set_status (plugin->cls,
@@ -5642,6 +5654,12 @@ test_kyc (void)
"https://exchange.net/",
1LLU,
now,
+ MHD_HTTP_OK,
+ TALER_EC_NONE,
+ NULL,
+ 0,
+ NULL,
+ false,
true));
fail = true;
TEST_RET_ON_FAIL (1 !=
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 3f27a138..96a3d001 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -79,6 +79,28 @@ struct TALER_MerchantAuthenticationSaltP
GNUNET_NETWORK_STRUCT_END
+/**
+ * Current exposed deposit limits by an exchange
+ * for a merchant (until other rules may apply).
+ */
+struct TALER_MERCHANTDB_DepositLimits
+{
+ /**
+ * Maximum amount to be deposited within @a timeframe.
+ */
+ struct TALER_Amount threshold;
+
+ /**
+ * Timeframe over which the limit applies.
+ */
+ struct GNUNET_TIME_Relative timeframe;
+
+ /**
+ * True if this is a soft limit that could be
+ * raised (by AML staff or by passing KYC checks).
+ */
+ bool soft_limit;
+};
/**
* Details about a wire account of the merchant.
@@ -512,9 +534,10 @@ struct TALER_MERCHANTDB_CategoryDetails
* @param event_type event of the webhook
*/
typedef void
-(*TALER_MERCHANTDB_WebhooksCallback)(void *cls,
- const char *webhook_id,
- const char *event_type);
+(*TALER_MERCHANTDB_WebhooksCallback)(
+ void *cls,
+ const char *webhook_id,
+ const char *event_type);
/**
@@ -1668,12 +1691,13 @@ struct TALER_MERCHANTDB_Plugin
* @return database result code
*/
enum GNUNET_DB_QueryStatus
- (*account_kyc_get_status)(void *cls,
- const char *merchant_id,
- const struct TALER_MerchantWireHashP *h_wire,
- const char *exchange_url,
- TALER_MERCHANTDB_KycCallback kyc_cb,
- void *kyc_cb_cls);
+ (*account_kyc_get_status)(
+ void *cls,
+ const char *merchant_id,
+ const struct TALER_MerchantWireHashP *h_wire,
+ const char *exchange_url,
+ TALER_MERCHANTDB_KycCallback kyc_cb,
+ void *kyc_cb_cls);
/**
* Update an instance's account's KYC status.
@@ -1684,6 +1708,12 @@ struct TALER_MERCHANTDB_Plugin
* @param exchange_url base URL of the exchange to check
* @param exchange_kyc_serial serial number for our account at the exchange (0 if unknown)
* @param timestamp timestamp to store
+ * @param exchange_http_status HTTP status code returned last by the exchange
+ * @param exchange_ec_code Taler error code returned last by the exchange
+ * @param access_token access token for the KYC process, NULL for none
+ * @param num_limits length of the @a limits array
+ * @param limits array with deposit limits returned by the exchange
+ * @param in_aml_review true if the exchange says the account is under review
* @param kyc_ok current KYC status (true for satisfied)
* @return database result code
*/
@@ -1695,6 +1725,12 @@ struct TALER_MERCHANTDB_Plugin
const char *exchange_url,
uint64_t exchange_kyc_serial,
struct GNUNET_TIME_Timestamp timestamp,
+ unsigned int exchage_http_status,
+ enum TALER_ErrorCode exchange_ec_code,
+ const struct TALER_AccountAccessTokenP *access_token,
+ unsigned int num_limits,
+ const struct TALER_MERCHANTDB_DepositLimits *limits,
+ bool in_aml_review,
bool kyc_ok);