merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/backend/taler-merchant-httpd_helper.h | 4++++
Msrc/backend/taler-merchant-httpd_private-post-orders.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/include/taler_merchant_util.h | 11+++++++++++
Msrc/util/contract_serialize.c | 13++++---------
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 (