merchant

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

taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c (7176B)


      1 /*
      2   This file is part of TALER
      3   (C) 2020, 2021 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation; either version 3,
      8   or (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,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file src/backend/taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c
     22  * @brief implementing POST /products/$ID/lock request handling
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include "taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.h"
     27 #include "taler-merchant-httpd_helper.h"
     28 #include <taler/taler_json_lib.h>
     29 #include "merchant-database/expire_locks.h"
     30 #include "merchant-database/lock_product.h"
     31 #include "merchant-database/lookup_product.h"
     32 
     33 
     34 enum MHD_Result
     35 TMH_private_post_products_ID_lock (
     36   const struct TMH_RequestHandler *rh,
     37   struct MHD_Connection *connection,
     38   struct TMH_HandlerContext *hc)
     39 {
     40   struct TMH_MerchantInstance *mi = hc->instance;
     41   const char *product_id = hc->infix;
     42   enum GNUNET_DB_QueryStatus qs;
     43   const char *uuids;
     44   struct GNUNET_Uuid uuid;
     45   uint64_t quantity;
     46   bool quantity_missing;
     47   const char *unit_quantity = NULL;
     48   bool unit_quantity_missing = true;
     49   struct GNUNET_TIME_Relative duration;
     50   struct GNUNET_JSON_Specification spec[] = {
     51     GNUNET_JSON_spec_string ("lock_uuid",
     52                              &uuids),
     53     GNUNET_JSON_spec_relative_time ("duration",
     54                                     &duration),
     55     GNUNET_JSON_spec_mark_optional (
     56       GNUNET_JSON_spec_uint64 ("quantity",
     57                                &quantity),
     58       &quantity_missing),
     59     GNUNET_JSON_spec_mark_optional (
     60       GNUNET_JSON_spec_string ("unit_quantity",
     61                                &unit_quantity),
     62       &unit_quantity_missing),
     63     GNUNET_JSON_spec_end ()
     64   };
     65 
     66   GNUNET_assert (NULL != mi);
     67   GNUNET_assert (NULL != product_id);
     68   {
     69     enum GNUNET_GenericReturnValue res;
     70 
     71     res = TALER_MHD_parse_json_data (connection,
     72                                      hc->request_body,
     73                                      spec);
     74     if (GNUNET_OK != res)
     75       return (GNUNET_NO == res)
     76              ? MHD_YES
     77              : MHD_NO;
     78   }
     79   TMH_uuid_from_string (uuids,
     80                         &uuid);
     81   TALER_MERCHANTDB_expire_locks (TMH_db);
     82   {
     83     struct TALER_MERCHANTDB_ProductDetails pd = { 0 };
     84     size_t num_categories;
     85     uint64_t *categories;
     86     uint64_t normalized_quantity = 0;
     87     uint32_t normalized_quantity_frac = 0;
     88 
     89     if (quantity_missing && unit_quantity_missing)
     90     {
     91       quantity = 1;
     92       quantity_missing = false;
     93     }
     94     else if ( (! quantity_missing) &&
     95               (quantity > (uint64_t) INT64_MAX) )
     96     {
     97       GNUNET_break_op (0);
     98       return TALER_MHD_reply_with_error (connection,
     99                                          MHD_HTTP_BAD_REQUEST,
    100                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
    101                                          "quantity");
    102     }
    103 
    104     qs = TALER_MERCHANTDB_lookup_product (TMH_db,
    105                                           mi->settings.id,
    106                                           product_id,
    107                                           &pd,
    108                                           &num_categories,
    109                                           &categories);
    110     switch (qs)
    111     {
    112     case GNUNET_DB_STATUS_HARD_ERROR:
    113       GNUNET_break (0);
    114       TALER_MERCHANTDB_product_details_free (&pd);
    115       GNUNET_free (categories);
    116       return TALER_MHD_reply_with_error (
    117         connection,
    118         MHD_HTTP_INTERNAL_SERVER_ERROR,
    119         TALER_EC_GENERIC_DB_FETCH_FAILED,
    120         "lookup_product");
    121     case GNUNET_DB_STATUS_SOFT_ERROR:
    122       GNUNET_break (0);
    123       TALER_MERCHANTDB_product_details_free (&pd);
    124       GNUNET_free (categories);
    125       return TALER_MHD_reply_with_error (
    126         connection,
    127         MHD_HTTP_INTERNAL_SERVER_ERROR,
    128         TALER_EC_GENERIC_DB_SOFT_FAILURE,
    129         "lookup_product");
    130     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    131       GNUNET_break_op (0);
    132       TALER_MERCHANTDB_product_details_free (&pd);
    133       GNUNET_free (categories);
    134       return TALER_MHD_reply_with_error (
    135         connection,
    136         MHD_HTTP_NOT_FOUND,
    137         TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN,
    138         product_id);
    139     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    140       break;
    141     }
    142     GNUNET_free (categories);
    143     {
    144       const char *eparam;
    145       if (GNUNET_OK !=
    146           TALER_MERCHANT_vk_process_quantity_inputs (
    147             TALER_MERCHANT_VK_QUANTITY,
    148             pd.allow_fractional_quantity,
    149             quantity_missing,
    150             (int64_t) quantity,
    151             unit_quantity_missing,
    152             unit_quantity,
    153             &normalized_quantity,
    154             &normalized_quantity_frac,
    155             &eparam))
    156       {
    157         TALER_MERCHANTDB_product_details_free (&pd);
    158         GNUNET_break_op (0);
    159         return TALER_MHD_reply_with_error (connection,
    160                                            MHD_HTTP_BAD_REQUEST,
    161                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    162                                            eparam);
    163       }
    164     }
    165     quantity = normalized_quantity;
    166     qs = TALER_MERCHANTDB_lock_product (TMH_db,
    167                                         mi->settings.id,
    168                                         product_id,
    169                                         &uuid,
    170                                         quantity,
    171                                         normalized_quantity_frac,
    172                                         GNUNET_TIME_relative_to_timestamp (duration));
    173     TALER_MERCHANTDB_product_details_free (&pd);
    174   }
    175   switch (qs)
    176   {
    177   case GNUNET_DB_STATUS_HARD_ERROR:
    178     GNUNET_break (0);
    179     return TALER_MHD_reply_with_error (
    180       connection,
    181       MHD_HTTP_INTERNAL_SERVER_ERROR,
    182       TALER_EC_GENERIC_DB_STORE_FAILED,
    183       NULL);
    184   case GNUNET_DB_STATUS_SOFT_ERROR:
    185     GNUNET_break (0);
    186     return TALER_MHD_reply_with_error (
    187       connection,
    188       MHD_HTTP_INTERNAL_SERVER_ERROR,
    189       TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    190       "Serialization error for single-statment request");
    191   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    192     GNUNET_break_op (0);
    193     return TALER_MHD_reply_with_error (
    194       connection,
    195       MHD_HTTP_GONE,
    196       TALER_EC_MERCHANT_PRIVATE_POST_PRODUCTS_LOCK_INSUFFICIENT_STOCKS,
    197       product_id);
    198   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    199     return TALER_MHD_reply_static (connection,
    200                                    MHD_HTTP_NO_CONTENT,
    201                                    NULL,
    202                                    NULL,
    203                                    0);
    204   }
    205   GNUNET_assert (0);
    206   return MHD_NO;
    207 }
    208 
    209 
    210 /* end of taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c */