commit 75e3b7d5eca3b32073f3c90b14a53a6100fb0be4
parent 214994750ba655d3cc4234b1bd757e06e903ba8e
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 27 Nov 2025 16:03:21 +0100
new EC
Diffstat:
4 files changed, 94 insertions(+), 12 deletions(-)
diff --git a/contrib/typst/vqf_902_1_customer.typ b/contrib/typst/vqf_902_1_customer.typ
@@ -28,6 +28,11 @@
data.at(key, default: default)
}
+ // Helper function to get value or false
+ let getb(key, default: false) = {
+ data.at(key, default: default)
+ }
+
// Helper function for checkbox
let checkbox(checked) = {
box(
@@ -413,9 +418,9 @@
inset: 5pt,
checkbox("" != get("CUSTOMER_ID_AMLA_FILE_REFERENCE_NO")), [Customer identification documents (or: reference#footnote[If the identification document is lists kept in another AMLA-File (in the case of Art. 15 para. 3 SRO Regulations) a reference to the according AMLA-File is sufficient.] to AMLA File No.: #underline([#get("CUSTOMER_ID_AMLA_FILE_REFERENCE_NO")]))],
checkbox("" != get("ESTABLISHER_ID_AMLA_FILE_REFERENCE_NO")), [Identification document of persons establishing the business relationship (or: reference to AMLA File No.: #underline([#get("ESTABLISHER_ID_AMLA_FILE_REFERENCE_NO")]))],
-// checkbox(get("HAVE_VQF_902_9") or get("HAVE_vqf_902_11") or get("HAVE_vqf_902_12") or get("HAVE_vqf_902_13") or get("HAVE_vqf_902_15")), [Establishing of the beneficial owner of the assets/controlling person (VQF Doc No. 902.15, 902.9, 902.11, 902.12 or 902.13)],
-// checkbox(get("HAVE_vqf_902_5")), [Customer profile (VQF doc. No. 902.5; only in the case of permanent business relationship and regular customers)],
-// checkbox(get("HAVE_vqf_902_4")), [Risk profile (VQF doc. No. 902.4)],
+ checkbox(getb("HAVE_vqf_902_9") or getb("HAVE_vqf_902_11") or getb("HAVE_vqf_902_12") or getb("HAVE_vqf_902_13") or getb("HAVE_vqf_902_15")), [Establishing of the beneficial owner of the assets/controlling person (VQF Doc No. 902.15, 902.9, 902.11, 902.12 or 902.13)],
+ checkbox(getb("HAVE_vqf_902_5")), [Customer profile (VQF doc. No. 902.5; only in the case of permanent business relationship and regular customers)],
+ checkbox(getb("HAVE_vqf_902_4")), [Risk profile (VQF doc. No. 902.4)],
)
v(1em)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -212,6 +212,11 @@ char *TEH_obg_url;
static char *toplevel_redirect_url;
/**
+ * Form data to inject into any Typst form generation.
+ */
+json_t *TEH_global_pdf_form_data;
+
+/**
* Our currency.
*/
char *TEH_currency;
@@ -2442,6 +2447,32 @@ exchange_serve_process_config (const char *cfg_fn)
GNUNET_free (attr_enc_key_str);
}
+ {
+ char *pdf_data;
+
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange",
+ "GLOBAL_PDF_FORM_DATA",
+ &pdf_data))
+ {
+ json_error_t err;
+
+ TEH_global_pdf_form_data = json_loads (pdf_data,
+ JSON_REJECT_DUPLICATES,
+ &err);
+ GNUNET_free (pdf_data);
+ if (NULL == TEH_global_pdf_form_data)
+ {
+ GNUNET_log_config_malformed (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "GLOBAL_PDF_FORM_DATA",
+ err.text);
+ return GNUNET_SYSERR;
+ }
+ }
+ }
+
for (unsigned int i = 0; i<MAX_DB_RETRIES; i++)
{
TEH_plugin = TALER_EXCHANGEDB_plugin_load (TEH_cfg,
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
@@ -170,6 +170,11 @@ extern float TEH_stefan_lin;
extern const struct TALER_CurrencySpecification *TEH_cspec;
/**
+ * Form data to inject into any Typst form generation.
+ */
+json_t *TEH_global_pdf_form_data;
+
+/**
* Our currency.
*/
extern char *TEH_currency;
diff --git a/src/exchange/taler-exchange-httpd_aml-attributes-get.c b/src/exchange/taler-exchange-httpd_aml-attributes-get.c
@@ -111,6 +111,12 @@ struct ResponseContext
* Next write offset into @e docs and @e jdata.
*/
size_t off;
+
+ /**
+ * Global attributes we need to inject in to each @e jdata.
+ */
+ json_t *global_attrs;
+
} pdf;
} details;
@@ -171,6 +177,7 @@ free_rc (struct TEH_RequestContext *rc)
case RCF_PDF:
for (size_t i = 0; i<rctx->details.pdf.off; i++)
json_decref (rctx->details.pdf.jdata[i]);
+ json_decref (rctx->details.pdf.global_attrs);
break;
}
GNUNET_free (rctx);
@@ -243,10 +250,18 @@ detail_cb (
json_object_set_new (attrs,
"DATADIR",
json_string (datadir)));
- // FIXME: add FILE_NUMBER to attrs (=> need it in rc first!)
- // FIXME: add VQF_MEMBER_NUMBER and possibly other meta data to attrs!
- // (need new config option for VQF_MEMBER_NUMBER-style globals!)
-
+ {
+ char *have;
+
+ GNUNET_asprintf (&have,
+ "HAVE_%s",
+ form_id);
+ GNUNET_assert (0 ==
+ json_object_set_new (rc->pdf.global_attrs,
+ have,
+ json_true ()));
+ GNUNET_free (have);
+ }
// FIXME: probably should move this into a helper function,
// we'll need it in various places:
rc->details.pdf.jdata[rc->details.pdf.off]
@@ -296,6 +311,25 @@ pdf_cb (void *cls,
}
+/**
+ * Adds cross-reference data to each @a doc that are only available
+ * in @a rctx after we have processed all inputs.
+ *
+ * @param rctx global context
+ * @param doc document to modify
+ */
+static void
+post_process_pdf (struct ResponseContext *rctx,
+ struct TALER_MHD_TypstDocument *doc)
+{
+ json_t *attrs = doc->attrs;
+
+ GNUNET_assert (0 ==
+ json_object_update_missing (attrs,
+ rctx->pdf.global_attrs));
+}
+
+
MHD_RESULT
TEH_handler_aml_attributes_get (
struct TEH_RequestContext *rc,
@@ -379,6 +413,12 @@ TEH_handler_aml_attributes_get (
"application/pdf"))
{
rctx->format = RCF_PDF;
+ rctx->details.pdf.global_attrs = json_array ();
+ GNUNET_assert (NULL != rctx->details.pdf.global_attrs);
+ if (NULL != TEH_global_pdf_form_data)
+ GNUNET_assert (0 ==
+ json_object_update (attrs,
+ TEH_global_pdf_form_data));
// FIXME: need to obtain globals about the
// account here first, like the FILE_NUMBER.
// Might just as well select current rules/etc
@@ -451,6 +491,9 @@ TEH_handler_aml_attributes_get (
NULL,
0);
}
+ for (unsigned int i = 0; i<rctx->details.pdf.off; i++)
+ post_process_pdf (rctx,
+ &rctx->details.pdf.docs[i]);
GNUNET_CONTAINER_DLL_insert (rctx_head,
rctx_tail,
rctx);
@@ -466,13 +509,11 @@ TEH_handler_aml_attributes_get (
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Client requested PDF, but Typst is unavailable\n");
- // FIXME: return JSON...
- return TALER_MHD_reply_static (
+ return TALER_MHD_reply_with_error (
rc->connection,
MHD_HTTP_NOT_IMPLEMENTED,
- NULL,
- NULL,
- 0);
+ TALER_EC_EXCHANGE_GENERIC_NO_TYPST_OR_PDFTK,
+ NULL);
}
return MHD_YES;
}