commit c2f8c5cb8ed9c8c1073e6c487ac2d63186b6b63f
parent 7501c7ae60c302e4074fc0d56ead1c22f05aaf4c
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 29 Dec 2025 05:23:39 +0100
add logic to parse money pot data in inventory products
Diffstat:
4 files changed, 82 insertions(+), 30 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_helper.h b/src/backend/taler-merchant-httpd_helper.h
@@ -66,6 +66,8 @@ TMH_location_object_valid (const json_t *location);
* Check if @a products is an array of valid Product(s) in the sense of
* Taler's API definition.
*
+ * FIXME: use TALER_MERCHANT_parse_product() instead?
+ *
* @param products array to check
* @return true if @a products is an array and all
* entries are valid Products.
@@ -189,6 +191,8 @@ TMH_format_fractional_string (enum TMH_ValueKind kind,
* only the syntax and that it properly claims to
* be an image.
*
+ * FIXME: move to libtalermerchantutil and use in TALER_MERCHANT_parse_product?
+ *
* @param image_data_url string to check
* @return true if @a image_data_url is a data
* URL with an "image/" mime-type
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -139,6 +139,12 @@ struct InventoryProduct
* True if the string quantity field was missing in the request.
*/
bool unit_quantity_missing;
+
+ /**
+ * Money pot associated with the product. 0 for none.
+ */
+ uint64_t product_money_pot;
+
};
@@ -223,7 +229,7 @@ struct WireMethodCandidate
struct OrderContext
{
/**
- * Information set in the ORDER_PHASE_PARSE_REQUEST phase.
+ * Information set in the #ORDER_PHASE_PARSE_REQUEST phase.
*/
struct
{
@@ -294,7 +300,7 @@ struct OrderContext
} parse_request;
/**
- * Information set in the ORDER_PHASE_PARSE_ORDER phase.
+ * Information set in the #ORDER_PHASE_PARSE_ORDER phase.
*/
struct
{
@@ -332,9 +338,14 @@ struct OrderContext
const json_t *fulfillment_message_i18n;
/**
- * Array of products that are part of the purchase.
- */
- const json_t *products;
+ * Length of the @e products array.
+ */
+ size_t products_len;
+
+ /**
+ * Array of products that are part of the purchase.
+ */
+ struct TALER_MERCHANT_Product *products;
/**
* URL where the same contract could be ordered again (if available).
@@ -445,7 +456,7 @@ struct OrderContext
} parse_order;
/**
- * Information set in the ORDER_PHASE_PARSE_CHOICES phase.
+ * Information set in the #ORDER_PHASE_PARSE_CHOICES phase.
*/
struct
{
@@ -473,7 +484,7 @@ struct OrderContext
} parse_choices;
/**
- * Information set in the ORDER_PHASE_MERGE_INVENTORY phase.
+ * Information set in the #ORDER_PHASE_MERGE_INVENTORY phase.
*/
struct
{
@@ -484,7 +495,7 @@ struct OrderContext
} merge_inventory;
/**
- * Information set in the ORDER_PHASE_ADD_PAYMENT_DETAILS phase.
+ * Information set in the #ORDER_PHASE_ADD_PAYMENT_DETAILS phase.
*/
struct
{
@@ -521,7 +532,7 @@ struct OrderContext
} add_payment_details;
/**
- * Information set in the ORDER_PHASE_SELECT_WIRE_METHOD phase.
+ * Information set in the #ORDER_PHASE_SELECT_WIRE_METHOD phase.
*/
struct
{
@@ -540,7 +551,7 @@ struct OrderContext
} select_wire_method;
/**
- * Information set in the ORDER_PHASE_SET_EXCHANGES phase.
+ * Information set in the #ORDER_PHASE_SET_EXCHANGES phase.
*/
struct
{
@@ -631,7 +642,7 @@ struct OrderContext
} set_exchanges;
/**
- * Information set in the ORDER_PHASE_SET_MAX_FEE phase.
+ * Information set in the #ORDER_PHASE_SET_MAX_FEE phase.
*/
struct
{
@@ -669,7 +680,7 @@ struct OrderContext
} set_max_fee;
/**
- * Information set in the ORDER_PHASE_EXECUTE_ORDER phase.
+ * Information set in the #ORDER_PHASE_EXECUTE_ORDER phase.
*/
struct
{
@@ -3278,12 +3289,15 @@ phase_merge_inventory (struct OrderContext *oc)
* parse_request.inventory_products => instructions to add products to contract terms
* parse_order.products => contains products that are not from the backend-managed inventory.
*/
- if (NULL != oc->parse_order.products)
- oc->merge_inventory.products
- = json_deep_copy (oc->parse_order.products);
- else
- oc->merge_inventory.products
- = json_array ();
+ oc->merge_inventory.products = json_array ();
+ for (size_t i = 0; i<oc->parse_order.products_len; i++)
+ {
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ oc->merge_inventory.products,
+ TALER_MERCHANT_product_serialize (&oc->parse_order.products[i])));
+ }
/* Populate products from inventory product array and database */
{
GNUNET_assert (NULL != oc->merge_inventory.products);
@@ -3755,6 +3769,7 @@ phase_parse_order (struct OrderContext *oc)
const char *merchant_base_url = NULL;
uint64_t version = 0;
const json_t *jmerchant = NULL;
+ const json_t *products = NULL;
const char *order_id = NULL;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
@@ -3765,7 +3780,7 @@ phase_parse_order (struct OrderContext *oc)
&oc->parse_order.summary),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_array_const ("products",
- &oc->parse_order.products),
+ &products),
NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("summary_i18n",
@@ -3853,6 +3868,27 @@ phase_parse_order (struct OrderContext *oc)
ret);
return;
}
+ if ( (NULL != products) &&
+ (0 != (oc->parse_order.products_len = json_array_size (products))) )
+ {
+ size_t i;
+ json_t *p;
+
+ json_array_foreach (products, i, p)
+ {
+ if (GNUNET_OK !=
+ TALER_MERCHANT_parse_product (p,
+ &oc->parse_order.products[i]))
+ {
+ GNUNET_break_op (0);
+ reply_with_error (oc,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "order.products");
+ return;
+ }
+ }
+ }
if (NULL != order_id)
{
size_t len = strlen (order_id);
@@ -4242,8 +4278,10 @@ phase_parse_order (struct OrderContext *oc)
oc->parse_order.merchant_base_url = url;
}
- if ( (NULL != oc->parse_order.products) &&
- (! TMH_products_array_valid (oc->parse_order.products)) )
+ // FIXME: integrate remaining validation logic with
+ // TALER_MERCHANT_parse_product() and then remove this!
+ if ( (NULL != products) &&
+ (! TMH_products_array_valid (products)) )
{
GNUNET_break_op (0);
reply_with_error (
@@ -4455,6 +4493,10 @@ phase_parse_request (struct OrderContext *oc)
GNUNET_JSON_spec_string ("unit_quantity",
&ipr->unit_quantity),
&ipr->unit_quantity_missing),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint64 ("product_money_pot",
+ &ipr->product_money_pot),
+ &ipr->quantity_missing),
GNUNET_JSON_spec_end ()
};
diff --git a/src/include/taler_merchant_util.h b/src/include/taler_merchant_util.h
@@ -1017,6 +1017,17 @@ TALER_MERCHANT_parse_choice_output (
/**
+ * Serialize @a p to JSON.
+ *
+ * @param p product to serialize
+ * @return JSON object representing the product @a p
+ */
+json_t *
+TALER_MERCHANT_product_serialize (
+ const struct TALER_MERCHANT_Product *p);
+
+
+/**
* Serialize contract terms into JSON object.
*
* @param[in] input contract terms to serialize
diff --git a/src/util/contract_serialize.c b/src/util/contract_serialize.c
@@ -385,14 +385,8 @@ json_from_contract_v1 (
}
-/**
- * Serialize @a p to JSON.
- *
- * @param p product to serialize
- * @return JSON object representing the product @a p
- */
-static json_t *
-product_serialize (
+json_t *
+TALER_MERCHANT_product_serialize (
const struct TALER_MERCHANT_Product *p)
{
return GNUNET_JSON_PACK (
@@ -474,7 +468,8 @@ success:
GNUNET_assert (
0 ==
json_array_append_new (products,
- product_serialize (&input->products[i])));
+ TALER_MERCHANT_product_serialize (
+ &input->products[i])));
}
return GNUNET_JSON_PACK (