commit 63e43ba0856ce50f833b20344f7d1dd38f699d7b
parent ebe98bd39046e88bb6b2605670cc38e425ccfe4e
Author: bohdan-potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date: Wed, 14 Jan 2026 01:37:46 +0100
some updates
Diffstat:
1 file changed, 1245 insertions(+), 783 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_post-using-templates.c b/src/backend/taler-merchant-httpd_post-using-templates.c
@@ -30,16 +30,145 @@
#include "taler-merchant-httpd_exchanges.h"
#include <taler/taler_json_lib.h>
-// FIXME: introduce PHASES (like we do in other handlers)
-// and break up the gigantic (and sometimes redundant)
-// handlers into clear parts, like parsing the request,
-// fetching template, checking inventory/computing price,
-// returning errors, etc.
+// FIXME: further split template-specific logic to reduce redundancy.
+// Make structs for each phase, so easier cleanup and more readable checks
+// add commented sections like in orders
+
+
+/**
+ * Context for inventory template processing.
+ */
+struct InventoryTemplateContext
+{
+ /**
+ * Selected products from inventory_selection.
+ */
+ struct InventoryTemplateItem
+ {
+ /**
+ * Product ID as referenced in inventory.
+ */
+ char *product_id;
+
+ /**
+ * Unit quantity string as provided by the client.
+ */
+ char *unit_quantity;
+
+ /**
+ * Parsed integer quantity.
+ */
+ uint64_t quantity_value;
+
+ /**
+ * Parsed fractional quantity.
+ */
+ uint32_t quantity_frac;
+
+ /**
+ * Product details from the DB (includes price array).
+ */
+ struct TALER_MERCHANTDB_ProductDetails pd;
+
+ /**
+ * Categories referenced by the product.
+ */
+ uint64_t *categories;
+
+ /**
+ * Length of @e categories.
+ */
+ size_t num_categories;
+ } *items;
+
+ /**
+ * Length of @e items.
+ */
+ unsigned int items_len;
+
+ /**
+ * Selected categories from the template contract.
+ */
+ const json_t *selected_categories;
+
+ /**
+ * Selected products from the template contract.
+ */
+ const json_t *selected_products;
+
+ /**
+ * Whether all products are selectable.
+ */
+ bool selected_all;
+
+ /**
+ * Optional pre-calculated amount provided by the client.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Optional tip amount.
+ */
+ struct TALER_Amount tip;
+
+ /**
+ * Currency totals shared across selected products.
+ * Without amount.currency
+ */
+ struct InventoryTemplateCurrency
+ {
+ /**
+ * Total amount for this currency (without tips)
+ */
+ struct TALER_Amount total;
+ } *currencies;
+
+ /**
+ * Length of @e currencies.
+ */
+ unsigned int currencies_len;
+};
/**
* Our context.
*/
+enum UsePhase
+{
+ /**
+ * Fetch template details from the database.
+ */
+ USE_PHASE_LOOKUP_TEMPLATE,
+ /**
+ * Parse request payload into context fields.
+ */
+ USE_PHASE_PARSE_REQUEST,
+ /**
+ * Load DB-backed details needed for verification.
+ */
+ USE_PHASE_DB_FETCH,
+ /**
+ * Validate request and template compatibility.
+ */
+ USE_PHASE_VERIFY,
+ /**
+ * Construct the internal order request body.
+ */
+ USE_PHASE_CREATE_ORDER,
+ /**
+ * Submit the order to the shared order handler.
+ */
+ USE_PHASE_SUBMIT_ORDER,
+ /**
+ * Finished successfully with MHD_YES.
+ */
+ USE_PHASE_FINISHED_MHD_YES,
+ /**
+ * Finished with MHD_NO.
+ */
+ USE_PHASE_FINISHED_MHD_NO
+};
+
struct UseContext
{
/**
@@ -49,6 +178,110 @@ struct UseContext
struct TMH_HandlerContext ihc;
/**
+ * Phase we are currently in.
+ */
+ enum UsePhase phase;
+
+ /**
+ * Template type from the contract.
+ */
+ enum TALER_MERCHANT_TemplateType template_type;
+
+ /**
+ * Summary override from request, if any.
+ */
+ const char *summary;
+
+ /**
+ * Fulfillment URL override from request, if any.
+ */
+ const char *fulfillment_url;
+
+ /**
+ * Fulfillment message override from request, if any.
+ */
+ const char *fulfillment_message;
+
+ /**
+ * Parsed fields for fixed-order templates.
+ */
+ struct
+ {
+ /**
+ * Amount provided by the client.
+ */
+ struct TALER_Amount amount;
+ /**
+ * Tip provided by the client.
+ */
+ struct TALER_Amount tip;
+ /**
+ * True if @e amount was not provided.
+ */
+ bool no_amount;
+ /**
+ * True if @e tip was not provided.
+ */
+ bool no_tip;
+ /**
+ * Summary from the template contract.
+ */
+ const char *tsummary;
+ /**
+ * Currency from the template contract.
+ */
+ const char *tcurrency;
+ /**
+ * Amount from the template contract.
+ */
+ struct TALER_Amount tamount;
+ /**
+ * True if @e tamount was not provided.
+ */
+ bool no_tamount;
+ /**
+ * True if no summary override was provided.
+ */
+ bool no_summary;
+ } fixed;
+
+ /**
+ * Parsed fields for inventory templates.
+ */
+ struct
+ {
+ /**
+ * True if @e amount was not provided.
+ */
+ bool no_amount;
+ /**
+ * True if @e tip was not provided.
+ */
+ bool no_tip;
+ /**
+ * Template requires exactly one selection.
+ */
+ bool choose_one;
+ /**
+ * Template allows tips.
+ */
+ bool request_tip;
+ /**
+ * Summary from the template contract.
+ */
+ const char *tsummary;
+ /**
+ * True if no summary override was provided.
+ */
+ bool no_summary;
+ } inventory;
+
+ /**
+ * Inventory template processing context.
+ */
+ struct InventoryTemplateContext itc;
+
+ /**
* Our template details from the DB.
*/
struct TALER_MERCHANTDB_TemplateDetails etp;
@@ -60,6 +293,10 @@ struct UseContext
};
+static void
+cleanup_inventory_template_context (void *cls);
+
+
/**
* Clean up a `struct UseContext *`
*
@@ -71,6 +308,7 @@ cleanup_use_context (void *cls)
struct UseContext *uc = cls;
TALER_MERCHANTDB_template_details_free (&uc->etp);
+ cleanup_inventory_template_context (&uc->itc);
if (NULL != uc->ihc.cc)
uc->ihc.cc (uc->ihc.ctx);
json_decref (uc->ihc.request_body);
@@ -79,6 +317,66 @@ cleanup_use_context (void *cls)
/**
+ * Finalize a template use request.
+ *
+ * @param[in,out] uc use context
+ * @param ret handler return value
+ */
+static void
+use_finalize (struct UseContext *uc,
+ MHD_RESULT ret)
+{
+ uc->phase = (MHD_YES == ret)
+ ? USE_PHASE_FINISHED_MHD_YES
+ : USE_PHASE_FINISHED_MHD_NO;
+}
+
+
+/**
+ * Finalize after JSON parsing result.
+ *
+ * @param[in,out] uc use context
+ * @param res parse result
+ */
+static void
+use_finalize_parse (struct UseContext *uc,
+ enum GNUNET_GenericReturnValue res)
+{
+ use_finalize (uc,
+ (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO);
+}
+
+
+/**
+ * Reply with error and finalize the request.
+ *
+ * @param[in,out] uc use context
+ * @param connection connection to reply on
+ * @param http_status HTTP status code
+ * @param ec error code
+ * @param detail error detail
+ */
+static void
+use_reply_with_error (struct UseContext *uc,
+ struct MHD_Connection *connection,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const char *detail)
+{
+ MHD_RESULT mret;
+
+ mret = TALER_MHD_reply_with_error (connection,
+ http_status,
+ ec,
+ detail);
+ use_finalize (uc,
+ mret);
+}
+
+
+/**
* Check if a product ID appears in the selected_products list.
*
* @param selected_products JSON array of selected product IDs, may be NULL
@@ -160,19 +458,29 @@ compute_line_total (const struct TALER_Amount *unit_price,
{
struct TALER_Amount tmp;
- if (quantity > UINT32_MAX)
- return GNUNET_SYSERR;
if (GNUNET_OK !=
TALER_amount_set_zero (unit_price->currency,
line_total))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_line_total: failed to init total for currency %s\n",
+ unit_price->currency);
return GNUNET_SYSERR;
+ }
if (0 != quantity)
{
if (0 >
TALER_amount_multiply (line_total,
unit_price,
(uint32_t) quantity))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_line_total: multiply failed for quantity %lu"
+ " in %s\n",
+ quantity,
+ unit_price->currency);
return GNUNET_SYSERR;
+ }
}
if (0 != quantity_frac)
{
@@ -180,7 +488,13 @@ compute_line_total (const struct TALER_Amount *unit_price,
TALER_amount_multiply (&tmp,
unit_price,
quantity_frac))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_line_total: frac multiply failed for frac %u in %s\n",
+ quantity_frac,
+ unit_price->currency);
return GNUNET_SYSERR;
+ }
TALER_amount_divide (&tmp,
&tmp,
TALER_MERCHANT_UNIT_FRAC_BASE);
@@ -188,152 +502,49 @@ compute_line_total (const struct TALER_Amount *unit_price,
TALER_amount_add (line_total,
line_total,
&tmp))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_line_total: frac add failed in %s\n",
+ unit_price->currency);
return GNUNET_SYSERR;
+ }
}
return GNUNET_OK;
}
/**
- * Context for inventory template processing.
+ * Clean up a `struct InventoryTemplateContext *`.
+ *
+ * @param cls a `struct InventoryTemplateContext *`
*/
-struct InventoryTemplateContext
+static void
+cleanup_inventory_template_context (void *cls)
{
- /**
- * Selected products from inventory_selection.
- */
- struct InventoryTemplateItem
- {
- /**
- * Product ID as referenced in inventory.
- */
- char *product_id;
-
- /**
- * Unit quantity string as provided by the client.
- */
- char *unit_quantity;
+ struct InventoryTemplateContext *ctx = cls;
- /**
- * Parsed integer quantity.
- */
- uint64_t quantity_value;
+ if (NULL == ctx)
+ return;
+ for (unsigned int i = 0; i < ctx->items_len; i++)
+ {
+ struct InventoryTemplateItem *item = &ctx->items[i];
- /**
- * Parsed fractional quantity.
- */
- uint32_t quantity_frac;
-
- /**
- * Product details from the DB (includes price array).
- */
- struct TALER_MERCHANTDB_ProductDetails pd;
- } *items;
-
- /**
- * Length of @e items.
- */
- unsigned int items_len;
-
- /**
- * Selected categories from the template contract.
- */
- const json_t *selected_categories;
-
- /**
- * Selected products from the template contract.
- */
- const json_t *selected_products;
-
- /**
- * Whether all products are selectable.
- */
- bool selected_all;
-
- /**
- * Amount provided by the client.
- * FIXME: I don't see it in the spec that the client MUST provide this amount.
- */
- struct TALER_Amount amount;
-
- /**
- * Optional tip amount.
- */
- struct TALER_Amount tip;
-
- /**
- * Total amount for the requested currency (includes tip when present).
- *
- * FIXME: this makes no sense, we MAY still have multiple choices
- * (and thus different totals!) *if* the user didn't specify a tip
- * and there are products in multiple currencies!
- */
- struct TALER_Amount total;
-
- /**
- * Currency totals shared across selected products.
- * Without amount.currency
- */
- struct InventoryTemplateCurrency
- {
- /**
- * Currency string.
- */
- char *currency;
-
- /**
- * Total amount for this currency (without tips).
- */
- struct TALER_Amount total;
- } *currencies;
-
- /**
- * Length of @e currencies.
- */
- unsigned int currencies_len;
-};
-
-
-/**
- * Clean up a `struct InventoryTemplateContext *`.
- *
- * @param cls a `struct InventoryTemplateContext *`
- */
-static void
-cleanup_inventory_template_context (void *cls)
-{
- struct InventoryTemplateContext *ctx = cls;
-
- if (NULL == ctx)
- return;
- for (unsigned int i = 0; i < ctx->items_len; i++)
- {
- struct InventoryTemplateItem *item = &ctx->items[i];
-
- GNUNET_free (item->product_id);
- GNUNET_free (item->unit_quantity);
- TALER_MERCHANTDB_product_details_free (&item->pd);
- }
- GNUNET_free (ctx->items);
- for (unsigned int i = 0; i < ctx->currencies_len; i++)
- GNUNET_free (ctx->currencies[i].currency);
- GNUNET_free (ctx->currencies);
- memset (ctx,
- 0,
- sizeof (*ctx));
-}
+ GNUNET_free (item->product_id);
+ GNUNET_free (item->unit_quantity);
+ TALER_MERCHANTDB_product_details_free (&item->pd);
+ GNUNET_free (item->categories);
+ }
+ GNUNET_free (ctx->items);
+ GNUNET_free (ctx->currencies);
+ memset (ctx,
+ 0,
+ sizeof (*ctx));
+}
/**
* Compute totals for all currencies shared across selected products.
*
- * FIXME: this is wild. If the client _already_ provided an "amount"
- * this is pointless: we know the currency the payment will be made in.
- * (but should still check the total, alas below you just 'skip'
- * if the currency matches the client-given amount);
- * However, if the client did NOT give us an amount, we need to compute
- * per-currency totals.
- *
* @param[in,out] ctx inventory template context
* @return #GNUNET_OK on success
*/
@@ -352,17 +563,12 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
{
const char *currency = ctx->items[0].pd.price_array[i].currency;
- if (0 == strcmp (currency,
- ctx->amount.currency))
- continue;
-
if (! TMH_test_exchange_configured_for_currency (currency))
continue;
+
GNUNET_array_append (ctx->currencies,
ctx->currencies_len,
- (struct InventoryTemplateCurrency) {
- .currency = GNUNET_strdup (currency)
- });
+ (struct InventoryTemplateCurrency) { 0 });
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (currency,
&ctx->currencies[ctx->currencies_len
@@ -370,12 +576,10 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
}
if (0 == ctx->currencies_len)
- return GNUNET_OK; // If there is only main currency, all good we just return
+ return GNUNET_OK;
- /* Just loop through items, for each item check that all currencies from item[0]
- is in this item, if not remove the currency, in the process pre-calculate
- total per currency except the requested currency */
- for (unsigned int i = 1; i < ctx->items_len; i++)
+ /* Loop through items, ensure each currency exists and sum totals. */
+ for (unsigned int i = 0; i < ctx->items_len; i++)
{
const struct InventoryTemplateItem *item = &ctx->items[i];
for (unsigned int c = 0; c < ctx->currencies_len;)
@@ -385,7 +589,7 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
for (size_t j = 0; j < item->pd.price_array_length; j++)
{
if (0 == strcmp (item->pd.price_array[j].currency,
- ctx->currencies[c].currency))
+ ctx->currencies[c].total.currency))
{
unit_price = &item->pd.price_array[j];
break;
@@ -393,8 +597,7 @@ compute_totals_per_currency (struct InventoryTemplateContext *ctx)
}
if (NULL == unit_price)
{
- // FIXME: some logging would be nice...
- GNUNET_free (ctx->currencies[c].currency);
+ /* Just drop the currency, that we can't find in one of the items*/
ctx->currencies[c] = ctx->currencies[ctx->currencies_len - 1];
ctx->currencies_len--;
continue;
@@ -435,10 +638,21 @@ compute_inventory_total (const struct InventoryTemplateContext *ctx,
{
struct TALER_Amount line_total;
+ if (NULL == currency)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_inventory_total: currency is NULL\n");
+ return GNUNET_SYSERR;
+ }
if (GNUNET_OK !=
TALER_amount_set_zero (currency,
total))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_inventory_total: failed to init total for %s\n",
+ currency);
return GNUNET_SYSERR;
+ }
for (unsigned int i = 0; i < ctx->items_len; i++)
{
const struct InventoryTemplateItem *item = &ctx->items[i];
@@ -454,18 +668,36 @@ compute_inventory_total (const struct InventoryTemplateContext *ctx,
}
}
if (NULL == unit_price)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_inventory_total: missing price in %s for %s\n",
+ currency,
+ item->product_id);
return GNUNET_SYSERR;
+ }
if (GNUNET_OK !=
compute_line_total (unit_price,
item->quantity_value,
item->quantity_frac,
&line_total))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_inventory_total: line total failed for %s in %s\n",
+ item->product_id,
+ currency);
return GNUNET_SYSERR;
+ }
if (0 >
TALER_amount_add (total,
total,
&line_total))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "compute_inventory_total: add failed for %s in %s\n",
+ item->product_id,
+ currency);
return GNUNET_SYSERR;
+ }
}
return GNUNET_OK;
@@ -473,60 +705,41 @@ compute_inventory_total (const struct InventoryTemplateContext *ctx,
/**
- * Handle POST /templates/$ID for inventory templates.
+ * Parse request data for inventory templates.
*
* @param connection connection to reply on
* @param hc handler context
* @param uc use context
- * @param summary summary override (optional)
- * @param fulfillment_url fulfillment URL (optional)
- * @param fulfillment_message fulfillment message (optional)
- * @return MHD result
+ * @return #GNUNET_OK on success
*/
-static MHD_RESULT
-handle_using_templates_inventory (struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc,
- struct UseContext *uc,
- const char *summary,
- const char *fulfillment_url,
- const char *fulfillment_message)
+static enum GNUNET_GenericReturnValue
+parse_using_templates_inventory_request (struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc,
+ struct UseContext *uc)
{
- struct TMH_MerchantInstance *mi = hc->instance;
const json_t *inventory_selection = NULL;
- const char *tsummary = NULL;
- bool no_tip;
- bool choose_one = false;
- bool request_tip = false;
- bool no_summary;
- struct InventoryTemplateContext itc;
+ cleanup_inventory_template_context (&uc->itc);
+ uc->summary = NULL;
+ uc->inventory.no_amount = false;
+ uc->inventory.no_tip = false;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("summary",
- &summary),
+ &uc->summary),
NULL),
- // FIXME: spec clearly says "amount" is *optional*!
- // The (very common!) new inventory-cart case is one
- // where the client did NOT specify any currency yet
- // (unless tipping, I guess), and we should still
- // generate a v1 order with choices for different
- // currencies.
- TALER_JSON_spec_amount_any ("amount",
- &itc.amount),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any ("amount",
+ &uc->itc.amount),
+ &uc->inventory.no_amount),
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("tip",
- &itc.tip),
- &no_tip),
+ &uc->itc.tip),
+ &uc->inventory.no_tip),
GNUNET_JSON_spec_array_const ("inventory_selection",
&inventory_selection),
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue res;
- json_t *inventory_products;
- json_t *tip_products = NULL;
-
- memset (&itc,
- 0,
- sizeof (itc));
res = TALER_MHD_parse_json_data (connection,
hc->request_body,
@@ -534,150 +747,52 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
+ use_finalize_parse (uc,
+ res);
+ return GNUNET_SYSERR;
}
+ if ( (! uc->inventory.no_amount) ||
+ (! uc->inventory.no_tip) )
{
- struct GNUNET_JSON_Specification tcspec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("summary",
- &tsummary),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("selected_categories",
- &itc.selected_categories),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("selected_products",
- &itc.selected_products),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_bool ("choose_one",
- &choose_one),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_bool ("request_tip",
- &request_tip),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_bool ("selected_all",
- &itc.selected_all),
- NULL),
- GNUNET_JSON_spec_end ()
- };
- const char *err_name;
- unsigned int err_line;
-
- res = GNUNET_JSON_parse (uc->etp.template_contract,
- tcspec,
- &err_name,
- &err_line);
- if (GNUNET_OK != res)
+ if (! TMH_test_exchange_configured_for_currency (
+ (! uc->inventory.no_amount)
+ ? uc->itc.amount.currency
+ : uc->itc.tip.currency))
{
- GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- err_name);
+ GNUNET_break_op (0);
+ cleanup_inventory_template_context (&uc->itc);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ "Currency for amount is not supported by backend");
+ return GNUNET_SYSERR;
}
}
- if ( (NULL != summary) &&
- (NULL != tsummary) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_SUMMARY_CONFLICT_TEMPLATES_CONTRACT_SUBJECT,
- NULL);
- }
- if ( (NULL == summary) &&
- (NULL == tsummary) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_SUMMARY,
- NULL);
- }
- no_summary = (NULL == summary);
-
- if (! no_tip && ! request_tip)
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "tip");
- }
-
- if (! TMH_test_exchange_configured_for_currency (itc.amount.currency))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- "Currency for amount is not supported by backend");
- }
-
- if (! no_tip)
+ if (! uc->inventory.no_tip)
{
- if (GNUNET_YES !=
- TALER_amount_cmp_currency (&itc.amount,
- &itc.tip))
+ if (! uc->inventory.no_amount &&
+ (GNUNET_YES !=
+ TALER_amount_cmp_currency (&uc->itc.amount,
+ &uc->itc.tip)))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- "Mismatch of currencies between the amount and tip");
+ cleanup_inventory_template_context (&uc->itc);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ "Mismatch of currencies between the amount and tip");
+ return GNUNET_SYSERR;
}
}
- if (0 == json_array_size (inventory_selection))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MISSING,
- "inventory_selection");
- }
- if (choose_one &&
- (1 != json_array_size (inventory_selection)))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "inventory_selection");
- }
-
for (size_t i = 0; i < json_array_size (inventory_selection); i++)
{
const char *product_id;
const char *quantity;
- struct TALER_MERCHANTDB_ProductDetails pd;
- enum GNUNET_DB_QueryStatus qs;
- size_t num_categories = 0;
- uint64_t *categories = NULL;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("product_id",
&product_id),
@@ -687,9 +802,6 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
};
const char *err_name;
unsigned int err_line;
- uint64_t quantity_value = 0;
- uint32_t quantity_frac = 0;
- const char *eparam = NULL;
res = GNUNET_JSON_parse (json_array_get (inventory_selection,
i),
@@ -699,18 +811,69 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "inventory_selection");
+ cleanup_inventory_template_context (&uc->itc);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "inventory_selection");
+ return GNUNET_SYSERR;
+ }
+
+ {
+ struct InventoryTemplateItem item;
+
+ memset (&item,
+ 0,
+ sizeof (item));
+ item.product_id = GNUNET_strdup (product_id);
+ item.unit_quantity = GNUNET_strdup (quantity);
+ GNUNET_array_append (uc->itc.items,
+ uc->itc.items_len,
+ item);
}
+ }
+ if (0 == uc->itc.items_len)
+ {
+ GNUNET_break_op (0);
+ cleanup_inventory_template_context (&uc->itc);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ "inventory_selection");
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Fetch DB data for inventory templates.
+ *
+ * @param connection connection to reply on
+ * @param hc handler context
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+db_fetch_using_templates_inventory (struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc,
+ struct UseContext *uc)
+{
+ struct TMH_MerchantInstance *mi = hc->instance;
+
+ for (unsigned int i = 0; i < uc->itc.items_len; i++)
+ {
+ struct InventoryTemplateItem *item = &uc->itc.items[i];
+ struct TALER_MERCHANTDB_ProductDetails pd;
+ enum GNUNET_DB_QueryStatus qs;
+ size_t num_categories = 0;
+ uint64_t *categories = NULL;
qs = TMH_db->lookup_product (TMH_db->cls,
mi->settings.id,
- product_id,
+ item->product_id,
&pd,
&num_categories,
&categories);
@@ -736,160 +899,303 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_assert (0);
}
- GNUNET_JSON_parse_free (spec);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (connection,
- http_status,
- ec,
- product_id);
+ use_reply_with_error (uc,
+ connection,
+ http_status,
+ ec,
+ item->product_id);
+ return GNUNET_SYSERR;
}
- if (! itc.selected_all)
- {
- bool allowed = false;
+ item->pd = pd;
+ item->categories = categories;
+ item->num_categories = num_categories;
+ }
+ return GNUNET_OK;
+}
- if (product_id_selected (itc.selected_products,
- product_id))
- allowed = true;
- else if (categories_selected (itc.selected_categories,
- num_categories,
- categories))
- allowed = true;
- if (! allowed)
- {
- GNUNET_JSON_parse_free (spec);
- GNUNET_free (categories);
- TALER_MERCHANTDB_product_details_free (&pd);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "inventory_selection(selected product is not available for this template)");
- }
- }
+/**
+ * Verify request data for inventory templates.
+ *
+ * @param connection connection to reply on
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+verify_using_templates_inventory (struct MHD_Connection *connection,
+ struct UseContext *uc)
+{
+ struct GNUNET_JSON_Specification tcspec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("summary",
+ &uc->inventory.tsummary),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("selected_categories",
+ &uc->itc.selected_categories),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const ("selected_products",
+ &uc->itc.selected_products),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_bool ("choose_one",
+ &uc->inventory.choose_one),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_bool ("request_tip",
+ &uc->inventory.request_tip),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_bool ("selected_all",
+ &uc->itc.selected_all),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *err_name;
+ unsigned int err_line;
+ enum GNUNET_GenericReturnValue res;
- if (GNUNET_OK !=
- TALER_MERCHANT_vk_process_quantity_inputs (
- TMH_VK_QUANTITY,
- pd.allow_fractional_quantity,
- true,
- 0,
- false,
- quantity,
- &quantity_value,
- &quantity_frac,
- &eparam))
- {
- GNUNET_JSON_parse_free (spec);
- GNUNET_free (categories);
- TALER_MERCHANTDB_product_details_free (&pd);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- eparam);
- }
+ uc->inventory.tsummary = NULL;
+ uc->inventory.choose_one = false;
+ uc->inventory.request_tip = false;
+ uc->itc.selected_categories = NULL;
+ uc->itc.selected_products = NULL;
+ uc->itc.selected_all = false;
+
+ res = GNUNET_JSON_parse (uc->etp.template_contract,
+ tcspec,
+ &err_name,
+ &err_line);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ err_name);
+ return GNUNET_SYSERR;
+ }
- if (0 == pd.price_array_length)
- {
- GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
- GNUNET_free (categories);
- TALER_MERCHANTDB_product_details_free (&pd);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "price_array");
+ if ( (NULL != uc->summary) &&
+ (NULL != uc->inventory.tsummary) )
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_SUMMARY_CONFLICT_TEMPLATES_CONTRACT_SUBJECT,
+ NULL);
+ return GNUNET_SYSERR;
+ }
+ if ( (NULL == uc->summary) &&
+ (NULL == uc->inventory.tsummary) )
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_SUMMARY,
+ NULL);
+ return GNUNET_SYSERR;
+ }
+ uc->inventory.no_summary = (NULL == uc->summary);
+
+ if (! uc->inventory.no_tip &&
+ ! uc->inventory.request_tip)
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "tip");
+ return GNUNET_SYSERR;
+ }
+
+ if (uc->inventory.choose_one &&
+ (1 != uc->itc.items_len))
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "inventory_selection");
+ return GNUNET_SYSERR;
+ }
+
+ for (unsigned int i = 0; i < uc->itc.items_len; i++)
+ {
+ struct InventoryTemplateItem *item = &uc->itc.items[i];
+ const char *eparam = NULL;
+
+ if (! uc->itc.selected_all)
+ {
+ bool allowed = false;
+
+ if (product_id_selected (uc->itc.selected_products,
+ item->product_id))
+ allowed = true;
+ else if (categories_selected (uc->itc.selected_categories,
+ item->num_categories,
+ item->categories))
+ allowed = true;
+
+ if (! allowed)
+ {
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "inventory_selection(selected product is not available for this template)");
+ return GNUNET_SYSERR;
+ }
}
+ if (GNUNET_OK !=
+ TALER_MERCHANT_vk_process_quantity_inputs (
+ TMH_VK_QUANTITY,
+ item->pd.allow_fractional_quantity,
+ true,
+ 0,
+ false,
+ item->unit_quantity,
+ &item->quantity_value,
+ &item->quantity_frac,
+ &eparam))
{
- struct InventoryTemplateItem item;
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ eparam);
+ return GNUNET_SYSERR;
+ }
- memset (&item,
- 0,
- sizeof (item));
- item.product_id = GNUNET_strdup (product_id);
- item.unit_quantity = GNUNET_strdup (quantity);
- item.quantity_value = quantity_value;
- item.quantity_frac = quantity_frac;
- item.pd = pd;
- GNUNET_array_append (itc.items,
- itc.items_len,
- item);
- memset (&pd,
- 0,
- sizeof (pd));
- GNUNET_free (categories);
- categories = NULL;
+ if (0 == item->pd.price_array_length)
+ {
+ GNUNET_break (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "price_array");
+ return GNUNET_SYSERR;
}
}
- if (GNUNET_OK !=
- compute_totals_per_currency (&itc))
+ if (uc->inventory.no_amount &&
+ uc->inventory.no_tip)
{
- GNUNET_JSON_parse_free (spec);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "calculation of currency totals failed");
+ if (GNUNET_OK !=
+ compute_totals_per_currency (&uc->itc))
+ {
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "calculation of currency totals failed");
+ return GNUNET_SYSERR;
+ }
}
- // FIXME: itc.amount MAY not have been specified by the client here,
- // we MAY still be in a multi-currency scenario. You cannot just
- // use itc.amount
- if (GNUNET_OK !=
- compute_inventory_total (&itc,
- itc.amount.currency,
- &itc.total))
+ if (! uc->inventory.no_amount ||
+ ! uc->inventory.no_tip)
{
- GNUNET_JSON_parse_free (spec);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "total amount calculation failed");
+ const char *primary_currency = uc->inventory.no_amount
+ ? uc->itc.tip.currency
+ : uc->itc.amount.currency;
+
+ GNUNET_array_append (uc->itc.currencies,
+ uc->itc.currencies_len,
+ (struct InventoryTemplateCurrency) { 0 });
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (primary_currency,
+ &uc->itc.currencies[0].total));
+ if (GNUNET_OK !=
+ compute_inventory_total (&uc->itc,
+ primary_currency,
+ &uc->itc.currencies[0].total))
+ {
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "total amount calculation failed");
+ return GNUNET_SYSERR;
+ }
}
- if (! no_tip)
+ if (! uc->inventory.no_tip)
{
- // TODO: HMMMMM... If we have tip, we can't really go for another choice...
- // or we will have to indicate it somehow in the wallet, when user changes the choice...
- // FIXME: yes, so if we have a tip, only generate that exact choice!
if (GNUNET_YES !=
- TALER_amount_cmp_currency (&itc.tip,
- &itc.total))
+ TALER_amount_cmp_currency (&uc->itc.tip,
+ &uc->itc.currencies[0].total))
{
+ /* YOU NEVER SUPPOSED TO REACH IT */
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- itc.tip.currency);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ uc->itc.tip.currency);
+ return GNUNET_SYSERR;
}
if (0 >
- TALER_amount_add (&itc.total,
- &itc.total,
- &itc.tip))
+ TALER_amount_add (&uc->itc.currencies[0].total,
+ &uc->itc.currencies[0].total,
+ &uc->itc.tip))
{
GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
- "tip");
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
+ "tip");
+ return GNUNET_SYSERR;
}
+ }
+
+ if (! uc->inventory.no_amount &&
+ (0 != TALER_amount_cmp (&uc->itc.amount,
+ &uc->itc.currencies[0].total)))
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_AMOUNT_CONFLICT_TEMPLATES_CONTRACT_AMOUNT,
+ NULL);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Create order request for inventory templates.
+ *
+ * @param connection connection to reply on
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+create_using_templates_inventory (struct UseContext *uc)
+{
+ json_t *inventory_products;
+ json_t *tip_products = NULL;
+ const bool multi_choices = uc->inventory.no_amount && uc->inventory.no_tip;
+
+ if (NULL != uc->ihc.request_body)
+ return GNUNET_OK;
+
+ if (! uc->inventory.no_tip)
+ {
tip_products = json_array ();
GNUNET_assert (0 ==
json_array_append_new (
@@ -900,28 +1206,14 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
GNUNET_JSON_pack_uint64 ("quantity",
1),
TALER_JSON_pack_amount ("price",
- &itc.tip))));
- }
-
- if (0 != TALER_amount_cmp (&itc.amount,
- &itc.total))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- json_decref (tip_products);
- cleanup_inventory_template_context (&itc);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_AMOUNT_CONFLICT_TEMPLATES_CONTRACT_AMOUNT,
- NULL);
+ &uc->itc.tip))));
}
inventory_products = json_array ();
GNUNET_assert (NULL != inventory_products);
- for (size_t i = 0; i < itc.items_len; i++)
+ for (size_t i = 0; i < uc->itc.items_len; i++)
{
- const struct InventoryTemplateItem *item = &itc.items[i];
+ const struct InventoryTemplateItem *item = &uc->itc.items[i];
GNUNET_assert (0 ==
json_array_append_new (
@@ -939,24 +1231,28 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
choices = json_array ();
GNUNET_assert (NULL != choices);
- GNUNET_assert (0 ==
- json_array_append_new (choices,
- GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("amount",
- &itc.total))
- ));
-
- for (size_t i = 0; i < itc.currencies_len; i++)
+ if (! multi_choices)
{
- if (0 == strcmp (itc.currencies[i].currency,
- itc.amount.currency))
- continue;
GNUNET_assert (0 ==
- json_array_append_new (
- choices,
- GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("amount",
- &itc.currencies[i].total))));
+ json_array_append_new (choices,
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("amount",
+ &uc->itc.
+ currencies
+ [0].total))
+ ));
+ }
+ else
+ {
+ for (size_t i = 0; i < uc->itc.currencies_len; i++)
+ {
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ choices,
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("amount",
+ &uc->itc.currencies[i].total))));
+ }
}
body = GNUNET_JSON_PACK (
@@ -973,71 +1269,58 @@ handle_using_templates_inventory (struct MHD_Connection *connection,
GNUNET_JSON_pack_array_steal ("choices",
choices),
GNUNET_JSON_pack_string ("summary",
- no_summary
- ? tsummary
- : summary),
+ uc->inventory.no_summary
+ ? uc->inventory.tsummary
+ : uc->summary),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_url",
- fulfillment_url)),
+ uc->fulfillment_url)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_message",
- fulfillment_message)),
+ uc->fulfillment_message)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_array_steal ("products",
tip_products)))));
GNUNET_assert (NULL != body);
uc->ihc.request_body = body;
}
- cleanup_inventory_template_context (&itc);
- GNUNET_JSON_parse_free (spec);
- return TMH_private_post_orders (
- NULL, /* not even used */
- connection,
- &uc->ihc);
+ cleanup_inventory_template_context (&uc->itc);
+ return GNUNET_OK;
}
/**
- * Handle POST /templates/$ID for fixed-order templates.
+ * Parse request data for fixed-order templates.
*
* @param connection connection to reply on
* @param hc handler context
* @param uc use context
- * @param summary summary override (optional)
- * @param fulfillment_url fulfillment URL (optional)
- * @param fulfillment_message fulfillment message (optional)
- * @return MHD result
+ * @return #GNUNET_OK on success
*/
-static MHD_RESULT
-handle_using_templates_fixed (struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc,
- struct UseContext *uc,
- const char *summary,
- const char *fulfillment_url,
- const char *fulfillment_message)
+static enum GNUNET_GenericReturnValue
+parse_using_templates_fixed_request (struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc,
+ struct UseContext *uc)
{
- struct TALER_Amount amount;
- struct TALER_Amount tip;
- bool no_amount;
- bool no_tip;
- bool no_summary;
+ uc->summary = NULL;
+ uc->fixed.no_amount = false;
+ uc->fixed.no_tip = false;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_string ("summary",
- &summary),
+ &uc->summary),
NULL),
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("amount",
- &amount),
- &no_amount),
+ &uc->fixed.amount),
+ &uc->fixed.no_amount),
GNUNET_JSON_spec_mark_optional (
TALER_JSON_spec_amount_any ("tip",
- &tip),
- &no_tip),
+ &uc->fixed.tip),
+ &uc->fixed.no_tip),
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue res;
- json_t *tip_products = NULL;
res = TALER_MHD_parse_json_data (connection,
hc->request_body,
@@ -1045,223 +1328,270 @@ handle_using_templates_fixed (struct MHD_Connection *connection,
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
+ use_finalize_parse (uc,
+ res);
+ return GNUNET_SYSERR;
}
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify request data for fixed-order templates.
+ *
+ * @param connection connection to reply on
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+verify_using_templates_fixed (struct MHD_Connection *connection,
+ struct UseContext *uc)
+{
+ uint32_t min_age;
+ struct GNUNET_TIME_Relative pay_duration;
+ struct GNUNET_JSON_Specification tspec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("summary",
+ &uc->fixed.tsummary),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("currency",
+ &uc->fixed.tcurrency),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any ("amount",
+ &uc->fixed.tamount),
+ &uc->fixed.no_tamount),
+ GNUNET_JSON_spec_uint32 ("minimum_age",
+ &min_age),
+ GNUNET_JSON_spec_relative_time ("pay_duration",
+ &pay_duration),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+ const char *err_name;
+ unsigned int err_line;
- if (NULL == uc->ihc.request_body)
+ uc->fixed.tsummary = NULL;
+ uc->fixed.tcurrency = NULL;
+ uc->fixed.no_tamount = false;
+
+ res = GNUNET_JSON_parse (uc->etp.template_contract,
+ tspec,
+ &err_name,
+ &err_line);
+ if (GNUNET_OK != res)
{
- /* template */
- const char *tsummary = NULL;
- const char *tcurrency = NULL;
- uint32_t min_age;
- struct GNUNET_TIME_Relative pay_duration;
- struct TALER_Amount tamount;
- bool no_tamount;
- struct GNUNET_JSON_Specification tspec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("summary",
- &tsummary),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string ("currency",
- &tcurrency),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- TALER_JSON_spec_amount_any ("amount",
- &tamount),
- &no_tamount),
- GNUNET_JSON_spec_uint32 ("minimum_age",
- &min_age),
- GNUNET_JSON_spec_relative_time ("pay_duration",
- &pay_duration),
- GNUNET_JSON_spec_end ()
- };
+ GNUNET_break (0);
+ json_dumpf (uc->etp.template_contract,
+ stderr,
+ JSON_INDENT (2));
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ err_name);
+ return GNUNET_SYSERR;
+ }
- {
- const char *err_name;
- unsigned int err_line;
-
- res = GNUNET_JSON_parse (uc->etp.template_contract,
- tspec,
- &err_name,
- &err_line);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- json_dumpf (uc->etp.template_contract,
- stderr,
- JSON_INDENT (2));
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- err_name);
- }
- }
+ if ( (! uc->fixed.no_amount) &&
+ (! uc->fixed.no_tamount) )
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_AMOUNT_CONFLICT_TEMPLATES_CONTRACT_AMOUNT,
+ NULL);
+ return GNUNET_SYSERR;
+ }
- if ( (! no_amount) &&
- (! no_tamount) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_AMOUNT_CONFLICT_TEMPLATES_CONTRACT_AMOUNT,
- NULL);
- }
+ if ( (! uc->fixed.no_amount) &&
+ (NULL != uc->fixed.tcurrency) &&
+ (0 != strcmp (uc->fixed.tcurrency,
+ uc->fixed.amount.currency)) )
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ uc->fixed.tcurrency);
+ return GNUNET_SYSERR;
+ }
- if ( (! no_amount) &&
- (NULL != tcurrency) &&
- (0 != strcmp (tcurrency,
- amount.currency)) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- tcurrency);
- }
+ if (uc->fixed.no_amount && uc->fixed.no_tamount)
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_AMOUNT,
+ NULL);
+ return GNUNET_SYSERR;
+ }
+
+ if (! uc->fixed.no_tip)
+ {
+ const struct TALER_Amount *total_amount;
- if (no_amount && no_tamount)
+ total_amount = uc->fixed.no_amount
+ ? &uc->fixed.tamount
+ : &uc->fixed.amount;
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (&uc->fixed.tip,
+ total_amount))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_AMOUNT,
- NULL);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
+ uc->fixed.tip.currency);
+ return GNUNET_SYSERR;
}
+ }
- if (! no_tip)
- {
- const struct TALER_Amount *total_amount;
+ if ( (NULL != uc->summary) &&
+ (NULL != uc->fixed.tsummary) )
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_SUMMARY_CONFLICT_TEMPLATES_CONTRACT_SUBJECT,
+ NULL);
+ return GNUNET_SYSERR;
+ }
- total_amount = no_amount ? &tamount : &amount;
- if (GNUNET_YES !=
- TALER_amount_cmp_currency (&tip,
- total_amount))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- json_decref (tip_products);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH,
- tip.currency);
- }
- }
+ if ( (NULL == uc->summary) &&
+ (NULL == uc->fixed.tsummary) )
+ {
+ GNUNET_break_op (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_SUMMARY,
+ NULL);
+ return GNUNET_SYSERR;
+ }
+ uc->fixed.no_summary = (NULL == uc->summary);
- if ( (NULL != summary) &&
- (NULL != tsummary) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_SUMMARY_CONFLICT_TEMPLATES_CONTRACT_SUBJECT,
- NULL);
- }
+ return GNUNET_OK;
+}
- if ( (NULL == summary) &&
- (NULL == tsummary) )
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_MERCHANT_POST_USING_TEMPLATES_NO_SUMMARY,
- NULL);
- }
- no_summary = (NULL == summary);
- {
- json_t *body;
- if (! no_tip)
- {
- tip_products = json_array ();
- GNUNET_assert (NULL != tip_products);
- GNUNET_assert (0 ==
- json_array_append_new (
- tip_products,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("description",
- "tip"),
- GNUNET_JSON_pack_uint64 ("quantity",
- 1),
- TALER_JSON_pack_amount ("price",
- &tip))));
- }
- body = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("otp_id",
- uc->etp.otp_id)),
- GNUNET_JSON_pack_object_steal (
- "order",
- GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("amount",
- no_amount
- ? &tamount
- : &amount),
- GNUNET_JSON_pack_string ("summary",
- no_summary
- ? tsummary
- : summary),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("fulfillment_url",
- fulfillment_url)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("fulfillment_message",
- fulfillment_message)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_array_steal ("products",
- tip_products)))));
- uc->ihc.request_body = body;
- }
+/**
+ * Create order request for fixed-order templates.
+ *
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+create_using_templates_fixed (struct UseContext *uc)
+{
+ json_t *tip_products = NULL;
+
+ if (NULL != uc->ihc.request_body)
+ return GNUNET_OK;
+
+ if (! uc->fixed.no_tip)
+ {
+ tip_products = json_array ();
+ GNUNET_assert (NULL != tip_products);
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ tip_products,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("description",
+ "tip"),
+ GNUNET_JSON_pack_uint64 ("quantity",
+ 1),
+ TALER_JSON_pack_amount ("price",
+ &uc->fixed.tip))));
+ }
+ {
+ json_t *body;
+
+ body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("otp_id",
+ uc->etp.otp_id)),
+ GNUNET_JSON_pack_object_steal (
+ "order",
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("amount",
+ uc->fixed.no_amount
+ ? &uc->fixed.tamount
+ : &uc->fixed.amount),
+ GNUNET_JSON_pack_string ("summary",
+ uc->fixed.no_summary
+ ? uc->fixed.tsummary
+ : uc->summary),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("fulfillment_url",
+ uc->fulfillment_url)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("fulfillment_message",
+ uc->fulfillment_message)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_array_steal ("products",
+ tip_products)))));
+ uc->ihc.request_body = body;
}
- return TMH_private_post_orders (
- NULL, /* not even used */
- connection,
- &uc->ihc);
+ return GNUNET_OK;
}
/**
- * Handle POST /templates/$ID for paivana templates.
+ * Parse request data for paivana templates.
*
* @param connection connection to reply on
* @param hc handler context
* @param uc use context
- * @param summary summary override (optional)
- * @param fulfillment_url fulfillment URL (optional)
- * @param fulfillment_message fulfillment message (optional)
- * @return MHD result
+ * @return #GNUNET_OK on success
*/
-static MHD_RESULT
-handle_using_templates_paivana (struct MHD_Connection *connection,
- struct TMH_HandlerContext *hc,
- struct UseContext *uc,
- const char *summary,
- const char *fulfillment_url,
- const char *fulfillment_message)
+static enum GNUNET_GenericReturnValue
+parse_using_templates_paivana_request (struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc,
+ struct UseContext *uc)
{
/* TODO: PAIVANA include paivana_id in instantiation flow. */
- return handle_using_templates_fixed (connection,
- hc,
- uc,
- summary,
- fulfillment_url,
- fulfillment_message);
+ return parse_using_templates_fixed_request (connection,
+ hc,
+ uc);
+}
+
+
+/**
+ * Verify request data for paivana templates.
+ *
+ * @param connection connection to reply on
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+verify_using_templates_paivana (struct MHD_Connection *connection,
+ struct UseContext *uc)
+{
+ /* TODO: PAIVANA include paivana-specific verification. */
+ return verify_using_templates_fixed (connection,
+ uc);
+}
+
+
+/**
+ * Create order request for paivana templates.
+ *
+ * @param uc use context
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+create_using_templates_paivana (struct UseContext *uc)
+{
+ /* TODO: PAIVANA include paivana-specific order creation. */
+ return create_using_templates_fixed (uc);
}
@@ -1272,9 +1602,6 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
{
struct TMH_MerchantInstance *mi = hc->instance;
const char *template_id = hc->infix;
- const char *summary = NULL;
- const char *fulfillment_url = NULL;
- const char *fulfillment_message = NULL;
struct UseContext *uc = hc->ctx;
if (NULL == uc)
@@ -1283,82 +1610,217 @@ TMH_post_using_templates_ID (const struct TMH_RequestHandler *rh,
hc->ctx = uc;
hc->cc = &cleanup_use_context;
uc->ihc.instance = hc->instance;
+ uc->phase = USE_PHASE_LOOKUP_TEMPLATE;
+ uc->template_type = TALER_MERCHANT_TEMPLATE_TYPE_INVALID;
+ uc->summary = NULL;
+ uc->fulfillment_url = NULL;
+ uc->fulfillment_message = NULL;
}
- if (! uc->have_etp)
+ while (1)
{
- enum GNUNET_DB_QueryStatus qs;
-
- // FIXME: include template type in request, fully parse
- // request before even going into the DB.
- qs = TMH_db->lookup_template (TMH_db->cls,
- mi->settings.id,
- template_id,
- &uc->etp);
- switch (qs)
+ switch (uc->phase)
{
- case GNUNET_DB_STATUS_HARD_ERROR:
- /* Clean up and fail hard */
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL);
- case GNUNET_DB_STATUS_SOFT_ERROR:
- /* this should be impossible (single select) */
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL);
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* template not found! */
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
- template_id);
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* all good */
- uc->have_etp = true;
+ case USE_PHASE_LOOKUP_TEMPLATE:
+ if (! uc->have_etp)
+ {
+ enum GNUNET_DB_QueryStatus qs;
+
+ // FIXME: include template type in request, fully parse
+ // request before even going into the DB.
+ qs = TMH_db->lookup_template (TMH_db->cls,
+ mi->settings.id,
+ template_id,
+ &uc->etp);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ /* Clean up and fail hard */
+ GNUNET_break (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ break;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ /* this should be impossible (single select) */
+ GNUNET_break (0);
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ NULL);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* template not found! */
+ use_reply_with_error (uc,
+ connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_MERCHANT_GENERIC_TEMPLATE_UNKNOWN,
+ template_id);
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* all good */
+ uc->have_etp = true;
+ break;
+ } /* End of the switch */
+ if (! uc->have_etp)
+ break;
+ }
+ uc->template_type =
+ TMH_template_type_from_contract (uc->etp.template_contract);
+ if (TALER_MERCHANT_TEMPLATE_TYPE_INVALID == uc->template_type)
+ {
+ GNUNET_break (0);
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "template_contract has unexpected type");
+ break;
+ }
+ uc->phase = USE_PHASE_PARSE_REQUEST;
break;
- } /* End of the switch */
- }
- // FIXME: share more logic between these, just skip (or run) individual
- // phases depending on the template type!
- switch (TMH_template_type_from_contract (uc->etp.template_contract))
- {
- case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
- return handle_using_templates_fixed (connection,
- hc,
- uc,
- summary,
- fulfillment_url,
- fulfillment_message);
- case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
- /* TODO: PAIVANA handle paivana-specific instantiation. */
- return handle_using_templates_paivana (connection,
- hc,
- uc,
- summary,
- fulfillment_url,
- fulfillment_message);
- case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
- return handle_using_templates_inventory (connection,
- hc,
- uc,
- summary,
- fulfillment_url,
- fulfillment_message);
- case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
- break;
+ case USE_PHASE_PARSE_REQUEST:
+ {
+ enum GNUNET_GenericReturnValue res = GNUNET_SYSERR;
+
+ // FIXME: share more logic between these, just skip (or run) individual
+ // phases depending on the template type!
+ switch (uc->template_type)
+ {
+ case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
+ res = parse_using_templates_fixed_request (connection,
+ hc,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
+ /* TODO: PAIVANA handle paivana-specific instantiation. */
+ res = parse_using_templates_paivana_request (connection,
+ hc,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
+ res = parse_using_templates_inventory_request (connection,
+ hc,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
+ GNUNET_break (0);
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "template_contract has unexpected type");
+ break;
+ }
+ if (GNUNET_OK == res)
+ uc->phase = USE_PHASE_DB_FETCH;
+ break;
+ }
+ case USE_PHASE_DB_FETCH:
+ {
+ enum GNUNET_GenericReturnValue res = GNUNET_OK;
+
+ switch (uc->template_type)
+ {
+ case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
+ case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
+ res = db_fetch_using_templates_inventory (connection,
+ hc,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
+ GNUNET_break (0);
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "template_contract has unexpected type");
+ break;
+ }
+ if (GNUNET_OK == res)
+ uc->phase = USE_PHASE_VERIFY;
+ break;
+ }
+ case USE_PHASE_VERIFY:
+ {
+ enum GNUNET_GenericReturnValue res = GNUNET_SYSERR;
+
+ switch (uc->template_type)
+ {
+ case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
+ res = verify_using_templates_fixed (connection,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
+ /* TODO: PAIVANA handle paivana-specific instantiation. */
+ res = verify_using_templates_paivana (connection,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
+ res = verify_using_templates_inventory (connection,
+ uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
+ GNUNET_break (0);
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "template_contract has unexpected type");
+ break;
+ }
+ if (GNUNET_OK == res)
+ uc->phase = USE_PHASE_CREATE_ORDER;
+ break;
+ }
+ case USE_PHASE_CREATE_ORDER:
+ {
+ enum GNUNET_GenericReturnValue res = GNUNET_SYSERR;
+
+ switch (uc->template_type)
+ {
+ case TALER_MERCHANT_TEMPLATE_TYPE_FIXED_ORDER:
+ res = create_using_templates_fixed (uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
+ /* TODO: PAIVANA handle paivana-specific instantiation. */
+ res = create_using_templates_paivana (uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVENTORY_CART:
+ res = create_using_templates_inventory (uc);
+ break;
+ case TALER_MERCHANT_TEMPLATE_TYPE_INVALID:
+ GNUNET_break (0);
+ use_reply_with_error (
+ uc,
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ "template_contract has unexpected type");
+ break;
+ }
+ if (GNUNET_OK == res)
+ uc->phase = USE_PHASE_SUBMIT_ORDER;
+ break;
+ }
+ case USE_PHASE_SUBMIT_ORDER:
+ return TMH_private_post_orders (
+ NULL, /* not even used */
+ connection,
+ &uc->ihc);
+ case USE_PHASE_FINISHED_MHD_YES:
+ return MHD_YES;
+ case USE_PHASE_FINISHED_MHD_NO:
+ return MHD_NO;
+ }
}
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
- "template_contract has unexpected type");
}