merchant

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

testing_api_cmd_post_orders.c (32544B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU General Public License as
      7   published by the Free Software Foundation; either version 3, or
      8   (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file src/testing/testing_api_cmd_post_orders.c
     22  * @brief command to run POST /orders
     23  * @author Marcello Stanisci
     24  */
     25 
     26 #include "platform.h"
     27 struct OrdersState;
     28 #define TALER_MERCHANT_POST_PRIVATE_ORDERS_RESULT_CLOSURE struct OrdersState
     29 #define TALER_MERCHANT_POST_ORDERS_CLAIM_RESULT_CLOSURE struct OrdersState
     30 #include <gnunet/gnunet_common.h>
     31 #include <gnunet/gnunet_time_lib.h>
     32 #include <jansson.h>
     33 #include <stdint.h>
     34 #include "taler/taler_merchant_util.h"
     35 #include <stdlib.h>
     36 #include <math.h>
     37 #include <taler/taler_exchange_service.h>
     38 #include <taler/taler_testing_lib.h>
     39 #include "taler/taler_merchant_service.h"
     40 #include "taler/taler_merchant_testing_lib.h"
     41 #include <taler/merchant/post-private-orders.h>
     42 #include <taler/merchant/post-orders-ORDER_ID-claim.h>
     43 
     44 /**
     45  * State for a "POST /orders" CMD.
     46  */
     47 struct OrdersState
     48 {
     49 
     50   /**
     51    * Expected status code.
     52    */
     53   unsigned int http_status;
     54 
     55   /**
     56    * Order id.
     57    */
     58   const char *order_id;
     59 
     60   /**
     61    * Our configuration.
     62    */
     63   const struct GNUNET_CONFIGURATION_Handle *cfg;
     64 
     65   /**
     66    * The order id we expect the merchant to assign (if not NULL).
     67    */
     68   const char *expected_order_id;
     69 
     70   /**
     71    * Contract terms obtained from the backend.
     72    */
     73   json_t *contract_terms;
     74 
     75   /**
     76    * Order submitted to the backend.
     77    */
     78   json_t *order_terms;
     79 
     80   /**
     81    * Contract terms hash code.
     82    */
     83   struct TALER_PrivateContractHashP h_contract_terms;
     84 
     85   /**
     86    * The /orders operation handle.
     87    */
     88   struct TALER_MERCHANT_PostPrivateOrdersHandle *po;
     89 
     90   /**
     91    * The (initial) POST /orders/$ID/claim operation handle.
     92    * The logic is such that after an order creation,
     93    * we immediately claim the order.
     94    */
     95   struct TALER_MERCHANT_PostOrdersClaimHandle *och;
     96 
     97   /**
     98    * The nonce.
     99    */
    100   struct GNUNET_CRYPTO_EddsaPublicKey nonce;
    101 
    102   /**
    103    * Whether to generate a claim token.
    104    */
    105   bool make_claim_token;
    106 
    107   /**
    108    * The claim token
    109    */
    110   struct TALER_ClaimTokenP claim_token;
    111 
    112   /**
    113    * URL of the merchant backend.
    114    */
    115   const char *merchant_url;
    116 
    117   /**
    118    * The interpreter state.
    119    */
    120   struct TALER_TESTING_Interpreter *is;
    121 
    122   /**
    123    * Merchant signature over the orders.
    124    */
    125   struct TALER_MerchantSignatureP merchant_sig;
    126 
    127   /**
    128    * Merchant public key.
    129    */
    130   struct TALER_MerchantPublicKeyP merchant_pub;
    131 
    132   /**
    133    * The payment target for the order
    134    */
    135   const char *payment_target;
    136 
    137   /**
    138    * The products the order is purchasing.
    139    */
    140   const char *products;
    141 
    142   /**
    143    * The locks that the order should release.
    144    */
    145   const char *locks;
    146 
    147   /**
    148    * Should the command also CLAIM the order?
    149    */
    150   bool with_claim;
    151 
    152   /**
    153    * If not NULL, the command should duplicate the request and verify the
    154    * response is the same as in this command.
    155    */
    156   const char *duplicate_of;
    157 };
    158 
    159 
    160 /**
    161  * Offer internal data to other commands.
    162  *
    163  * @param cls closure
    164  * @param[out] ret result (could be anything)
    165  * @param trait name of the trait
    166  * @param index index number of the object to extract.
    167  * @return #GNUNET_OK on success
    168  */
    169 static enum GNUNET_GenericReturnValue
    170 orders_traits (void *cls,
    171                const void **ret,
    172                const char *trait,
    173                unsigned int index)
    174 {
    175   struct OrdersState *ps = cls;
    176   struct TALER_TESTING_Trait traits[] = {
    177     TALER_TESTING_make_trait_order_id (ps->order_id),
    178     TALER_TESTING_make_trait_contract_terms (ps->contract_terms),
    179     TALER_TESTING_make_trait_order_terms (ps->order_terms),
    180     TALER_TESTING_make_trait_h_contract_terms (&ps->h_contract_terms),
    181     TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
    182     TALER_TESTING_make_trait_merchant_pub (&ps->merchant_pub),
    183     TALER_TESTING_make_trait_claim_nonce (&ps->nonce),
    184     TALER_TESTING_make_trait_claim_token (&ps->claim_token),
    185     TALER_TESTING_trait_end ()
    186   };
    187 
    188   return TALER_TESTING_get_trait (traits,
    189                                   ret,
    190                                   trait,
    191                                   index);
    192 }
    193 
    194 
    195 /**
    196  * Used to fill the "orders" CMD state with backend-provided
    197  * values.  Also double-checks that the order was correctly
    198  * created.
    199  *
    200  * @param cls closure
    201  * @param ocr response we got
    202  */
    203 static void
    204 orders_claim_cb (struct OrdersState *ps,
    205                  const struct TALER_MERCHANT_PostOrdersClaimResponse *ocr)
    206 {
    207   const char *error_name;
    208   unsigned int error_line;
    209   struct GNUNET_JSON_Specification spec[] = {
    210     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
    211                                  &ps->merchant_pub),
    212     GNUNET_JSON_spec_end ()
    213   };
    214 
    215   ps->och = NULL;
    216   if (ps->http_status != ocr->hr.http_status)
    217   {
    218     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    219                 "Expected status %u, got %u\n",
    220                 ps->http_status,
    221                 ocr->hr.http_status);
    222     TALER_TESTING_FAIL (ps->is);
    223   }
    224   if (MHD_HTTP_OK != ocr->hr.http_status)
    225   {
    226     TALER_TESTING_interpreter_next (ps->is);
    227     return;
    228   }
    229   ps->contract_terms = json_deep_copy (
    230     (json_t *) ocr->details.ok.contract_terms);
    231   GNUNET_assert (GNUNET_OK ==
    232                  TALER_JSON_contract_hash (ps->contract_terms,
    233                                            &ps->h_contract_terms));
    234   ps->merchant_sig = ocr->details.ok.merchant_sig;
    235   if (GNUNET_OK !=
    236       GNUNET_JSON_parse (ps->contract_terms,
    237                          spec,
    238                          &error_name,
    239                          &error_line))
    240   {
    241     char *log;
    242 
    243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    244                 "Parser failed on %s:%u\n",
    245                 error_name,
    246                 error_line);
    247     log = json_dumps (ps->contract_terms,
    248                       JSON_INDENT (1));
    249     fprintf (stderr,
    250              "%s\n",
    251              log);
    252     free (log);
    253     TALER_TESTING_FAIL (ps->is);
    254   }
    255   TALER_TESTING_interpreter_next (ps->is);
    256 }
    257 
    258 
    259 /**
    260  * Callback that processes the response following a POST /orders.  NOTE: no
    261  * contract terms are included here; they need to be taken via the "orders
    262  * lookup" method.
    263  *
    264  * @param cls closure.
    265  * @param por details about the response
    266  */
    267 static void
    268 order_cb (struct OrdersState *ps,
    269           const struct TALER_MERCHANT_PostPrivateOrdersResponse *por)
    270 {
    271 
    272   ps->po = NULL;
    273   if (ps->http_status != por->hr.http_status)
    274   {
    275     TALER_TESTING_unexpected_status_with_body (ps->is,
    276                                                por->hr.http_status,
    277                                                ps->http_status,
    278                                                por->hr.reply);
    279     TALER_TESTING_interpreter_fail (ps->is);
    280     return;
    281   }
    282   switch (por->hr.http_status)
    283   {
    284   case 0:
    285     TALER_LOG_DEBUG ("/orders, expected 0 status code\n");
    286     TALER_TESTING_interpreter_next (ps->is);
    287     return;
    288   case MHD_HTTP_OK:
    289     if (NULL != por->details.ok.token)
    290       ps->claim_token = *por->details.ok.token;
    291     ps->order_id = GNUNET_strdup (por->details.ok.order_id);
    292     if ((NULL != ps->expected_order_id) &&
    293         (0 != strcmp (por->details.ok.order_id,
    294                       ps->expected_order_id)))
    295     {
    296       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    297                   "Order id assigned does not match\n");
    298       TALER_TESTING_interpreter_fail (ps->is);
    299       return;
    300     }
    301     if (NULL != ps->duplicate_of)
    302     {
    303       const struct TALER_TESTING_Command *order_cmd;
    304       const struct TALER_ClaimTokenP *prev_token;
    305       struct TALER_ClaimTokenP zero_token = {0};
    306 
    307       order_cmd = TALER_TESTING_interpreter_lookup_command (
    308         ps->is,
    309         ps->duplicate_of);
    310       if (GNUNET_OK !=
    311           TALER_TESTING_get_trait_claim_token (order_cmd,
    312                                                &prev_token))
    313       {
    314         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    315                     "Could not fetch previous order claim token\n");
    316         TALER_TESTING_interpreter_fail (ps->is);
    317         return;
    318       }
    319       if (NULL == por->details.ok.token)
    320         prev_token = &zero_token;
    321       if (0 != GNUNET_memcmp (prev_token,
    322                               por->details.ok.token))
    323       {
    324         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    325                     "Claim tokens for identical requests do not match\n");
    326         TALER_TESTING_interpreter_fail (ps->is);
    327         return;
    328       }
    329     }
    330     break;
    331   case MHD_HTTP_NOT_FOUND:
    332     TALER_TESTING_interpreter_next (ps->is);
    333     return;
    334   case MHD_HTTP_GONE:
    335     TALER_TESTING_interpreter_next (ps->is);
    336     return;
    337   case MHD_HTTP_CONFLICT:
    338     TALER_TESTING_interpreter_next (ps->is);
    339     return;
    340   default:
    341     {
    342       char *s = json_dumps (por->hr.reply,
    343                             JSON_COMPACT);
    344       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    345                   "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n",
    346                   por->hr.http_status,
    347                   (int) por->hr.ec,
    348                   TALER_TESTING_interpreter_get_current_label (ps->is),
    349                   s);
    350       free (s);
    351       /**
    352        * Not failing, as test cases are _supposed_
    353        * to create non 200 OK situations.
    354        */
    355       TALER_TESTING_interpreter_next (ps->is);
    356     }
    357     return;
    358   }
    359 
    360   if (! ps->with_claim)
    361   {
    362     TALER_TESTING_interpreter_next (ps->is);
    363     return;
    364   }
    365   ps->och = TALER_MERCHANT_post_orders_claim_create (
    366     TALER_TESTING_interpreter_get_context (ps->is),
    367     ps->merchant_url,
    368     ps->order_id,
    369     &ps->nonce);
    370   if (NULL == ps->och)
    371     TALER_TESTING_FAIL (ps->is);
    372   TALER_MERCHANT_post_orders_claim_set_options (
    373     ps->och,
    374     TALER_MERCHANT_post_orders_claim_option_token (
    375       &ps->claim_token));
    376   {
    377     enum TALER_ErrorCode ec;
    378 
    379     ec = TALER_MERCHANT_post_orders_claim_start (ps->och,
    380                                                  &orders_claim_cb,
    381                                                  ps);
    382     GNUNET_assert (TALER_EC_NONE == ec);
    383   }
    384 }
    385 
    386 
    387 /**
    388  * Run a "orders" CMD.
    389  *
    390  * @param cls closure.
    391  * @param cmd command currently being run.
    392  * @param is interpreter state.
    393  */
    394 static void
    395 orders_run (void *cls,
    396             const struct TALER_TESTING_Command *cmd,
    397             struct TALER_TESTING_Interpreter *is)
    398 {
    399   struct OrdersState *ps = cls;
    400 
    401   ps->is = is;
    402   if (NULL == json_object_get (ps->order_terms,
    403                                "order_id"))
    404   {
    405     struct GNUNET_TIME_Absolute now;
    406     char *order_id;
    407 
    408     now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
    409     order_id = GNUNET_STRINGS_data_to_string_alloc (
    410       &now,
    411       sizeof (now));
    412     GNUNET_assert (0 ==
    413                    json_object_set_new (ps->order_terms,
    414                                         "order_id",
    415                                         json_string (order_id)));
    416     GNUNET_free (order_id);
    417   }
    418   GNUNET_CRYPTO_random_block (&ps->nonce,
    419                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
    420   ps->po = TALER_MERCHANT_post_private_orders_create (
    421     TALER_TESTING_interpreter_get_context (is),
    422     ps->merchant_url,
    423     ps->order_terms);
    424   GNUNET_assert (NULL != ps->po);
    425   {
    426     enum TALER_ErrorCode ec;
    427 
    428     ec = TALER_MERCHANT_post_private_orders_start (ps->po,
    429                                                    &order_cb,
    430                                                    ps);
    431     GNUNET_assert (TALER_EC_NONE == ec);
    432   }
    433 }
    434 
    435 
    436 /**
    437  * Run a "orders" CMD.
    438  *
    439  * @param cls closure.
    440  * @param cmd command currently being run.
    441  * @param is interpreter state.
    442  */
    443 static void
    444 orders_run2 (void *cls,
    445              const struct TALER_TESTING_Command *cmd,
    446              struct TALER_TESTING_Interpreter *is)
    447 {
    448   struct OrdersState *ps = cls;
    449   const json_t *order;
    450   char *products_string = GNUNET_strdup (ps->products);
    451   char *locks_string = GNUNET_strdup (ps->locks);
    452   char *token;
    453   struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct *products = NULL;
    454   unsigned int products_length = 0;
    455   const char **locks = NULL;
    456   unsigned int locks_length = 0;
    457 
    458   ps->is = is;
    459   if (NULL != ps->duplicate_of)
    460   {
    461     const struct TALER_TESTING_Command *order_cmd;
    462     const json_t *ct;
    463 
    464     order_cmd = TALER_TESTING_interpreter_lookup_command (
    465       is,
    466       ps->duplicate_of);
    467     if (GNUNET_OK !=
    468         TALER_TESTING_get_trait_order_terms (order_cmd,
    469                                              &ct))
    470     {
    471       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    472                   "Could not fetch previous order string\n");
    473       TALER_TESTING_interpreter_fail (is);
    474       return;
    475     }
    476     order = (json_t *) ct;
    477   }
    478   else
    479   {
    480     if (NULL == json_object_get (ps->order_terms,
    481                                  "order_id"))
    482     {
    483       struct GNUNET_TIME_Absolute now;
    484       char *order_id;
    485 
    486       now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
    487       order_id = GNUNET_STRINGS_data_to_string_alloc (
    488         &now.abs_value_us,
    489         sizeof (now.abs_value_us));
    490       GNUNET_assert (0 ==
    491                      json_object_set_new (ps->order_terms,
    492                                           "order_id",
    493                                           json_string (order_id)));
    494       GNUNET_free (order_id);
    495     }
    496     order = ps->order_terms;
    497   }
    498   if (NULL == order)
    499   {
    500     GNUNET_break (0);
    501     TALER_TESTING_interpreter_fail (is);
    502     return;
    503   }
    504 
    505   GNUNET_CRYPTO_random_block (&ps->nonce,
    506                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
    507   for (token = strtok (products_string, ";");
    508        NULL != token;
    509        token = strtok (NULL, ";"))
    510   {
    511     char *ctok;
    512     struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct pd;
    513     double quantity_double = 0.0;
    514 
    515     /* Token syntax is "[product_id]/[quantity]" */
    516     ctok = strchr (token, '/');
    517     if (NULL != ctok)
    518     {
    519       *ctok = '\0';
    520       ctok++;
    521       {
    522         char *endptr;
    523 
    524         quantity_double = strtod (ctok,
    525                                   &endptr);
    526         if ( (endptr == ctok) || ('\0' != *endptr) ||
    527              (! isfinite (quantity_double)) || (quantity_double < 0.0))
    528         {
    529           GNUNET_break (0);
    530           break;
    531         }
    532       }
    533     }
    534     else
    535     {
    536       quantity_double = 1.0;
    537     }
    538     if (quantity_double <= 0.0)
    539     {
    540       GNUNET_break (0);
    541       break;
    542     }
    543 
    544     {
    545       double quantity_floor;
    546       double frac;
    547       uint64_t quantity_int;
    548       uint32_t quantity_frac_local = 0;
    549       long long scaled;
    550 
    551       quantity_floor = floor (quantity_double);
    552       frac = quantity_double - quantity_floor;
    553       quantity_int = (uint64_t) quantity_floor;
    554       if (frac < 0.0)
    555       {
    556         GNUNET_break (0);
    557         break;
    558       }
    559       scaled = llround (frac * (double) TALER_MERCHANT_UNIT_FRAC_BASE);
    560       if (scaled < 0)
    561       {
    562         GNUNET_break (0);
    563         break;
    564       }
    565       if (scaled >= (long long) TALER_MERCHANT_UNIT_FRAC_BASE)
    566       {
    567         quantity_int++;
    568         scaled -= TALER_MERCHANT_UNIT_FRAC_BASE;
    569       }
    570       quantity_frac_local = (uint32_t) scaled;
    571       pd.quantity = quantity_int;
    572       pd.quantity_frac = quantity_frac_local;
    573       pd.use_fractional_quantity = (0 != quantity_frac_local);
    574     }
    575     pd.product_id = token;
    576 
    577     GNUNET_array_append (products,
    578                          products_length,
    579                          pd);
    580   }
    581   for (token = strtok (locks_string, ";");
    582        NULL != token;
    583        token = strtok (NULL, ";"))
    584   {
    585     const struct TALER_TESTING_Command *lock_cmd;
    586     const char *uuid;
    587 
    588     lock_cmd = TALER_TESTING_interpreter_lookup_command (
    589       is,
    590       token);
    591 
    592     if (GNUNET_OK !=
    593         TALER_TESTING_get_trait_lock_uuid (lock_cmd,
    594                                            &uuid))
    595     {
    596       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    597                   "Could not fetch lock uuid\n");
    598       TALER_TESTING_interpreter_fail (is);
    599       return;
    600     }
    601 
    602     GNUNET_array_append (locks,
    603                          locks_length,
    604                          uuid);
    605   }
    606   ps->po = TALER_MERCHANT_post_private_orders_create (
    607     TALER_TESTING_interpreter_get_context (is),
    608     ps->merchant_url,
    609     order);
    610   GNUNET_assert (NULL != ps->po);
    611   if (NULL != ps->payment_target)
    612     TALER_MERCHANT_post_private_orders_set_options (
    613       ps->po,
    614       TALER_MERCHANT_post_private_orders_option_payment_target (
    615         ps->payment_target));
    616   if (0 < products_length)
    617     TALER_MERCHANT_post_private_orders_set_options (
    618       ps->po,
    619       TALER_MERCHANT_post_private_orders_option_inventory_products (
    620         products_length, products));
    621   if (0 < locks_length)
    622     TALER_MERCHANT_post_private_orders_set_options (
    623       ps->po,
    624       TALER_MERCHANT_post_private_orders_option_lock_uuids (
    625         locks_length, locks));
    626   TALER_MERCHANT_post_private_orders_set_options (
    627     ps->po,
    628     TALER_MERCHANT_post_private_orders_option_create_token (
    629       ps->make_claim_token));
    630   {
    631     enum TALER_ErrorCode ec;
    632 
    633     ec = TALER_MERCHANT_post_private_orders_start (ps->po,
    634                                                    &order_cb,
    635                                                    ps);
    636     GNUNET_assert (TALER_EC_NONE == ec);
    637   }
    638   GNUNET_free (products_string);
    639   GNUNET_free (locks_string);
    640   GNUNET_array_grow (products,
    641                      products_length,
    642                      0);
    643   GNUNET_array_grow (locks,
    644                      locks_length,
    645                      0);
    646 }
    647 
    648 
    649 /**
    650  * Run a "orders" CMD.
    651  *
    652  * @param cls closure.
    653  * @param cmd command currently being run.
    654  * @param is interpreter state.
    655  */
    656 static void
    657 orders_run3 (void *cls,
    658              const struct TALER_TESTING_Command *cmd,
    659              struct TALER_TESTING_Interpreter *is)
    660 {
    661   struct OrdersState *ps = cls;
    662   struct GNUNET_TIME_Absolute now;
    663 
    664   ps->is = is;
    665   now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
    666   if (NULL == json_object_get (ps->order_terms,
    667                                "order_id"))
    668   {
    669     char *order_id;
    670 
    671     order_id = GNUNET_STRINGS_data_to_string_alloc (
    672       &now,
    673       sizeof (now));
    674     GNUNET_assert (0 ==
    675                    json_object_set_new (ps->order_terms,
    676                                         "order_id",
    677                                         json_string (order_id)));
    678     GNUNET_free (order_id);
    679   }
    680 
    681   GNUNET_CRYPTO_random_block (&ps->nonce,
    682                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
    683   ps->po = TALER_MERCHANT_post_private_orders_create (
    684     TALER_TESTING_interpreter_get_context (is),
    685     ps->merchant_url,
    686     ps->order_terms);
    687   GNUNET_assert (NULL != ps->po);
    688   {
    689     enum TALER_ErrorCode ec;
    690 
    691     ec = TALER_MERCHANT_post_private_orders_start (ps->po,
    692                                                    &order_cb,
    693                                                    ps);
    694     GNUNET_assert (TALER_EC_NONE == ec);
    695   }
    696 }
    697 
    698 
    699 /**
    700  * Free the state of a "orders" CMD, and possibly
    701  * cancel it if it did not complete.
    702  *
    703  * @param cls closure.
    704  * @param cmd command being freed.
    705  */
    706 static void
    707 orders_cleanup (void *cls,
    708                 const struct TALER_TESTING_Command *cmd)
    709 {
    710   struct OrdersState *ps = cls;
    711 
    712   if (NULL != ps->po)
    713   {
    714     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    715                 "Command '%s' did not complete (orders put)\n",
    716                 cmd->label);
    717     TALER_MERCHANT_post_private_orders_cancel (ps->po);
    718     ps->po = NULL;
    719   }
    720 
    721   if (NULL != ps->och)
    722   {
    723     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    724                 "Command '%s' did not complete (orders lookup)\n",
    725                 cmd->label);
    726     TALER_MERCHANT_post_orders_claim_cancel (ps->och);
    727     ps->och = NULL;
    728   }
    729 
    730   json_decref (ps->contract_terms);
    731   json_decref (ps->order_terms);
    732   GNUNET_free_nz ((void *) ps->order_id);
    733   GNUNET_free (ps);
    734 }
    735 
    736 
    737 /**
    738  * Mark part of the contract terms as possible to forget.
    739  *
    740  * @param cls pointer to the result of the forget operation.
    741  * @param object_id name of the object to forget.
    742  * @param parent parent of the object at @e object_id.
    743  */
    744 static void
    745 mark_forgettable (void *cls,
    746                   const char *object_id,
    747                   json_t *parent)
    748 {
    749   GNUNET_assert (GNUNET_OK ==
    750                  TALER_JSON_contract_mark_forgettable (parent,
    751                                                        object_id));
    752 }
    753 
    754 
    755 /**
    756  * Constructs the json for a POST order request.
    757  *
    758  * @param order_id the name of the order to add, can be NULL.
    759  * @param refund_deadline the deadline for refunds on this order.
    760  * @param pay_deadline the deadline for payment on this order.
    761  * @param amount the amount this order is for, NULL for v1 orders
    762  * @param[out] order where to write the json string.
    763  */
    764 static void
    765 make_order_json (const char *order_id,
    766                  struct GNUNET_TIME_Timestamp refund_deadline,
    767                  struct GNUNET_TIME_Timestamp pay_deadline,
    768                  const char *amount,
    769                  json_t **order)
    770 {
    771   struct GNUNET_TIME_Timestamp refund = refund_deadline;
    772   struct GNUNET_TIME_Timestamp pay = pay_deadline;
    773   json_t *contract_terms;
    774 
    775   /* Include required fields and some dummy objects to test forgetting. */
    776   contract_terms = json_pack (
    777     "{s:s, s:s?, s:s?, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
    778     "summary", "merchant-lib testcase",
    779     "order_id", order_id,
    780     "amount", amount,
    781     "fulfillment_url", "https://example.com",
    782     "refund_deadline", GNUNET_JSON_from_timestamp (refund),
    783     "pay_deadline", GNUNET_JSON_from_timestamp (pay),
    784     "dummy_obj", "EUR:1.0",
    785     "dummy_array", /* For testing forgetting parts of arrays */
    786     "item", "speakers",
    787     "item", "headphones",
    788     "item", "earbuds");
    789   GNUNET_assert (GNUNET_OK ==
    790                  TALER_JSON_expand_path (contract_terms,
    791                                          "$.dummy_obj",
    792                                          &mark_forgettable,
    793                                          NULL));
    794   GNUNET_assert (GNUNET_OK ==
    795                  TALER_JSON_expand_path (contract_terms,
    796                                          "$.dummy_array[*].item",
    797                                          &mark_forgettable,
    798                                          NULL));
    799   *order = contract_terms;
    800 }
    801 
    802 
    803 struct TALER_TESTING_Command
    804 TALER_TESTING_cmd_merchant_post_orders_no_claim (
    805   const char *label,
    806   const char *merchant_url,
    807   unsigned int http_status,
    808   const char *order_id,
    809   struct GNUNET_TIME_Timestamp refund_deadline,
    810   struct GNUNET_TIME_Timestamp pay_deadline,
    811   const char *amount)
    812 {
    813   struct OrdersState *ps;
    814 
    815   ps = GNUNET_new (struct OrdersState);
    816   make_order_json (order_id,
    817                    refund_deadline,
    818                    pay_deadline,
    819                    amount,
    820                    &ps->order_terms);
    821   ps->http_status = http_status;
    822   ps->expected_order_id = order_id;
    823   ps->merchant_url = merchant_url;
    824   {
    825     struct TALER_TESTING_Command cmd = {
    826       .cls = ps,
    827       .label = label,
    828       .run = &orders_run,
    829       .cleanup = &orders_cleanup,
    830       .traits = &orders_traits
    831     };
    832 
    833     return cmd;
    834   }
    835 }
    836 
    837 
    838 struct TALER_TESTING_Command
    839 TALER_TESTING_cmd_merchant_post_orders (
    840   const char *label,
    841   const struct GNUNET_CONFIGURATION_Handle *cfg,
    842   const char *merchant_url,
    843   unsigned int http_status,
    844   const char *order_id,
    845   struct GNUNET_TIME_Timestamp refund_deadline,
    846   struct GNUNET_TIME_Timestamp pay_deadline,
    847   const char *amount)
    848 {
    849   struct OrdersState *ps;
    850 
    851   ps = GNUNET_new (struct OrdersState);
    852   ps->cfg = cfg;
    853   make_order_json (order_id,
    854                    refund_deadline,
    855                    pay_deadline,
    856                    amount,
    857                    &ps->order_terms);
    858   ps->http_status = http_status;
    859   ps->expected_order_id = order_id;
    860   ps->merchant_url = merchant_url;
    861   ps->with_claim = true;
    862   {
    863     struct TALER_TESTING_Command cmd = {
    864       .cls = ps,
    865       .label = label,
    866       .run = &orders_run,
    867       .cleanup = &orders_cleanup,
    868       .traits = &orders_traits
    869     };
    870 
    871     return cmd;
    872   }
    873 }
    874 
    875 
    876 struct TALER_TESTING_Command
    877 TALER_TESTING_cmd_merchant_post_orders2 (
    878   const char *label,
    879   const struct GNUNET_CONFIGURATION_Handle *cfg,
    880   const char *merchant_url,
    881   unsigned int http_status,
    882   const char *order_id,
    883   struct GNUNET_TIME_Timestamp refund_deadline,
    884   struct GNUNET_TIME_Timestamp pay_deadline,
    885   bool claim_token,
    886   const char *amount,
    887   const char *payment_target,
    888   const char *products,
    889   const char *locks,
    890   const char *duplicate_of)
    891 {
    892   struct OrdersState *ps;
    893 
    894   ps = GNUNET_new (struct OrdersState);
    895   ps->cfg = cfg;
    896   make_order_json (order_id,
    897                    refund_deadline,
    898                    pay_deadline,
    899                    amount,
    900                    &ps->order_terms);
    901   ps->http_status = http_status;
    902   ps->expected_order_id = order_id;
    903   ps->merchant_url = merchant_url;
    904   ps->payment_target = payment_target;
    905   ps->products = products;
    906   ps->locks = locks;
    907   ps->with_claim = (NULL == duplicate_of);
    908   ps->make_claim_token = claim_token;
    909   ps->duplicate_of = duplicate_of;
    910   {
    911     struct TALER_TESTING_Command cmd = {
    912       .cls = ps,
    913       .label = label,
    914       .run = &orders_run2,
    915       .cleanup = &orders_cleanup,
    916       .traits = &orders_traits
    917     };
    918 
    919     return cmd;
    920   }
    921 }
    922 
    923 
    924 struct TALER_TESTING_Command
    925 TALER_TESTING_cmd_merchant_post_orders3 (
    926   const char *label,
    927   const struct GNUNET_CONFIGURATION_Handle *cfg,
    928   const char *merchant_url,
    929   unsigned int expected_http_status,
    930   const char *order_id,
    931   struct GNUNET_TIME_Timestamp refund_deadline,
    932   struct GNUNET_TIME_Timestamp pay_deadline,
    933   const char *fulfillment_url,
    934   const char *amount)
    935 {
    936   struct OrdersState *ps;
    937 
    938   ps = GNUNET_new (struct OrdersState);
    939   ps->cfg = cfg;
    940   make_order_json (order_id,
    941                    refund_deadline,
    942                    pay_deadline,
    943                    amount,
    944                    &ps->order_terms);
    945   GNUNET_assert (0 ==
    946                  json_object_set_new (ps->order_terms,
    947                                       "fulfillment_url",
    948                                       json_string (fulfillment_url)));
    949   ps->http_status = expected_http_status;
    950   ps->merchant_url = merchant_url;
    951   ps->with_claim = true;
    952   {
    953     struct TALER_TESTING_Command cmd = {
    954       .cls = ps,
    955       .label = label,
    956       .run = &orders_run,
    957       .cleanup = &orders_cleanup,
    958       .traits = &orders_traits
    959     };
    960 
    961     return cmd;
    962   }
    963 }
    964 
    965 
    966 struct TALER_TESTING_Command
    967 TALER_TESTING_cmd_merchant_post_orders_choices (
    968   const char *label,
    969   const struct GNUNET_CONFIGURATION_Handle *cfg,
    970   const char *merchant_url,
    971   unsigned int http_status,
    972   const char *token_family_slug,
    973   const char *choice_description,
    974   json_t *choice_description_i18n,
    975   unsigned int num_inputs,
    976   unsigned int num_outputs,
    977   const char *order_id,
    978   struct GNUNET_TIME_Timestamp refund_deadline,
    979   struct GNUNET_TIME_Timestamp pay_deadline,
    980   const char *amount)
    981 {
    982   struct OrdersState *ps;
    983   struct TALER_Amount brutto;
    984   json_t *choice;
    985   json_t *choices;
    986   json_t *inputs;
    987   json_t *outputs;
    988 
    989   ps = GNUNET_new (struct OrdersState);
    990   ps->cfg = cfg;
    991   make_order_json (order_id,
    992                    refund_deadline,
    993                    pay_deadline,
    994                    NULL,
    995                    &ps->order_terms);
    996   GNUNET_assert (GNUNET_OK ==
    997                  TALER_string_to_amount (amount,
    998                                          &brutto));
    999   inputs = json_array ();
   1000   GNUNET_assert (NULL != inputs);
   1001   GNUNET_assert (0 ==
   1002                  json_array_append_new (
   1003                    inputs,
   1004                    GNUNET_JSON_PACK (
   1005                      GNUNET_JSON_pack_string ("type",
   1006                                               "token"),
   1007                      GNUNET_JSON_pack_uint64 ("count",
   1008                                               num_inputs),
   1009                      GNUNET_JSON_pack_string ("token_family_slug",
   1010                                               token_family_slug)
   1011                      )));
   1012   outputs = json_array ();
   1013   GNUNET_assert (NULL != outputs);
   1014   GNUNET_assert (0 ==
   1015                  json_array_append_new (
   1016                    outputs,
   1017                    GNUNET_JSON_PACK (
   1018                      GNUNET_JSON_pack_string ("type",
   1019                                               "token"),
   1020                      GNUNET_JSON_pack_uint64 ("count",
   1021                                               num_outputs),
   1022                      GNUNET_JSON_pack_string ("token_family_slug",
   1023                                               token_family_slug)
   1024                      )));
   1025   choice
   1026     = GNUNET_JSON_PACK (
   1027         TALER_JSON_pack_amount ("amount",
   1028                                 &brutto),
   1029         GNUNET_JSON_pack_allow_null (
   1030           GNUNET_JSON_pack_string ("description",
   1031                                    choice_description)),
   1032         GNUNET_JSON_pack_allow_null (
   1033           GNUNET_JSON_pack_object_steal ("description_i18n",
   1034                                          choice_description_i18n)),
   1035         GNUNET_JSON_pack_array_steal ("inputs",
   1036                                       inputs),
   1037         GNUNET_JSON_pack_array_steal ("outputs",
   1038                                       outputs));
   1039   choices = json_array ();
   1040   GNUNET_assert (NULL != choices);
   1041   GNUNET_assert (0 ==
   1042                  json_array_append_new (
   1043                    choices,
   1044                    choice));
   1045   GNUNET_assert (0 ==
   1046                  json_object_set_new (ps->order_terms,
   1047                                       "choices",
   1048                                       choices)
   1049                  );
   1050   GNUNET_assert (0 ==
   1051                  json_object_set_new (ps->order_terms,
   1052                                       "version",
   1053                                       json_integer (1))
   1054                  );
   1055 
   1056 
   1057   ps->http_status = http_status;
   1058   ps->expected_order_id = order_id;
   1059   ps->merchant_url = merchant_url;
   1060   ps->with_claim = true;
   1061   {
   1062     struct TALER_TESTING_Command cmd = {
   1063       .cls = ps,
   1064       .label = label,
   1065       .run = &orders_run3,
   1066       .cleanup = &orders_cleanup,
   1067       .traits = &orders_traits
   1068     };
   1069 
   1070     return cmd;
   1071   }
   1072 }
   1073 
   1074 
   1075 struct TALER_TESTING_Command
   1076 TALER_TESTING_cmd_merchant_post_orders_donau (
   1077   const char *label,
   1078   const struct GNUNET_CONFIGURATION_Handle *cfg,
   1079   const char *merchant_url,
   1080   unsigned int http_status,
   1081   const char *order_id,
   1082   struct GNUNET_TIME_Timestamp refund_deadline,
   1083   struct GNUNET_TIME_Timestamp pay_deadline,
   1084   const char *amount)
   1085 {
   1086   struct OrdersState *ps;
   1087   struct TALER_Amount brutto;
   1088   json_t *choice;
   1089   json_t *choices;
   1090   json_t *outputs;
   1091 
   1092   ps = GNUNET_new (struct OrdersState);
   1093   ps->cfg = cfg;
   1094   make_order_json (order_id,
   1095                    refund_deadline,
   1096                    pay_deadline,
   1097                    NULL,
   1098                    &ps->order_terms);
   1099   GNUNET_assert (GNUNET_OK ==
   1100                  TALER_string_to_amount (amount,
   1101                                          &brutto));
   1102 
   1103   outputs = json_array ();
   1104   GNUNET_assert (NULL != outputs);
   1105   GNUNET_assert (0 ==
   1106                  json_array_append_new (
   1107                    outputs,
   1108                    GNUNET_JSON_PACK (
   1109                      GNUNET_JSON_pack_string ("type",
   1110                                               "tax-receipt")
   1111                      )));
   1112   choice
   1113     = GNUNET_JSON_PACK (
   1114         TALER_JSON_pack_amount ("amount",
   1115                                 &brutto),
   1116         GNUNET_JSON_pack_array_steal ("outputs",
   1117                                       outputs));
   1118   choices = json_array ();
   1119   GNUNET_assert (NULL != choices);
   1120   GNUNET_assert (0 ==
   1121                  json_array_append_new (
   1122                    choices,
   1123                    choice));
   1124   GNUNET_assert (0 ==
   1125                  json_object_set_new (ps->order_terms,
   1126                                       "choices",
   1127                                       choices)
   1128                  );
   1129   GNUNET_assert (0 ==
   1130                  json_object_set_new (ps->order_terms,
   1131                                       "version",
   1132                                       json_integer (1))
   1133                  );
   1134 
   1135 
   1136   ps->http_status = http_status;
   1137   ps->expected_order_id = order_id;
   1138   ps->merchant_url = merchant_url;
   1139   ps->with_claim = true;
   1140   {
   1141     struct TALER_TESTING_Command cmd = {
   1142       .cls = ps,
   1143       .label = label,
   1144       .run = &orders_run3,
   1145       .cleanup = &orders_cleanup,
   1146       .traits = &orders_traits
   1147     };
   1148 
   1149     return cmd;
   1150   }
   1151 }