merchant

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

taler-merchant-httpd_private-post-products-ID-lock.c (7069B)


      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 taler-merchant-httpd_private-post-products-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_private-post-products-ID-lock.h"
     27 #include "taler-merchant-httpd_helper.h"
     28 #include <taler/taler_json_lib.h>
     29 
     30 
     31 MHD_RESULT
     32 TMH_private_post_products_ID_lock (
     33   const struct TMH_RequestHandler *rh,
     34   struct MHD_Connection *connection,
     35   struct TMH_HandlerContext *hc)
     36 {
     37   struct TMH_MerchantInstance *mi = hc->instance;
     38   const char *product_id = hc->infix;
     39   enum GNUNET_DB_QueryStatus qs;
     40   const char *uuids;
     41   struct GNUNET_Uuid uuid;
     42   uint64_t quantity;
     43   bool quantity_missing;
     44   const char *unit_quantity = NULL;
     45   bool unit_quantity_missing = true;
     46   struct GNUNET_TIME_Relative duration;
     47   struct GNUNET_JSON_Specification spec[] = {
     48     GNUNET_JSON_spec_string ("lock_uuid",
     49                              &uuids),
     50     GNUNET_JSON_spec_relative_time ("duration",
     51                                     &duration),
     52     GNUNET_JSON_spec_mark_optional (
     53       GNUNET_JSON_spec_uint64 ("quantity",
     54                                &quantity),
     55       &quantity_missing),
     56     GNUNET_JSON_spec_mark_optional (
     57       GNUNET_JSON_spec_string ("unit_quantity",
     58                                &unit_quantity),
     59       &unit_quantity_missing),
     60     GNUNET_JSON_spec_end ()
     61   };
     62 
     63   GNUNET_assert (NULL != mi);
     64   GNUNET_assert (NULL != product_id);
     65   {
     66     enum GNUNET_GenericReturnValue res;
     67 
     68     res = TALER_MHD_parse_json_data (connection,
     69                                      hc->request_body,
     70                                      spec);
     71     if (GNUNET_OK != res)
     72       return (GNUNET_NO == res)
     73              ? MHD_YES
     74              : MHD_NO;
     75   }
     76   TMH_uuid_from_string (uuids,
     77                         &uuid);
     78   TMH_db->expire_locks (TMH_db->cls);
     79   {
     80     struct TALER_MERCHANTDB_ProductDetails pd = { 0 };
     81     size_t num_categories;
     82     uint64_t *categories;
     83     uint64_t normalized_quantity = 0;
     84     uint32_t normalized_quantity_frac = 0;
     85 
     86     if (quantity_missing && unit_quantity_missing)
     87     {
     88       quantity = 1;
     89       quantity_missing = false;
     90     }
     91     else if ( (! quantity_missing) &&
     92               (quantity > (uint64_t) INT64_MAX) )
     93     {
     94       GNUNET_break_op (0);
     95       return TALER_MHD_reply_with_error (connection,
     96                                          MHD_HTTP_BAD_REQUEST,
     97                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
     98                                          "quantity");
     99     }
    100 
    101     qs = TMH_db->lookup_product (TMH_db->cls,
    102                                  mi->settings.id,
    103                                  product_id,
    104                                  &pd,
    105                                  &num_categories,
    106                                  &categories);
    107     switch (qs)
    108     {
    109     case GNUNET_DB_STATUS_HARD_ERROR:
    110       GNUNET_break (0);
    111       TALER_MERCHANTDB_product_details_free (&pd);
    112       GNUNET_free (categories);
    113       return TALER_MHD_reply_with_error (
    114         connection,
    115         MHD_HTTP_INTERNAL_SERVER_ERROR,
    116         TALER_EC_GENERIC_DB_FETCH_FAILED,
    117         "lookup_product");
    118     case GNUNET_DB_STATUS_SOFT_ERROR:
    119       GNUNET_break (0);
    120       TALER_MERCHANTDB_product_details_free (&pd);
    121       GNUNET_free (categories);
    122       return TALER_MHD_reply_with_error (
    123         connection,
    124         MHD_HTTP_INTERNAL_SERVER_ERROR,
    125         TALER_EC_GENERIC_DB_SOFT_FAILURE,
    126         "lookup_product");
    127     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    128       GNUNET_break_op (0);
    129       TALER_MERCHANTDB_product_details_free (&pd);
    130       GNUNET_free (categories);
    131       return TALER_MHD_reply_with_error (
    132         connection,
    133         MHD_HTTP_NOT_FOUND,
    134         TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN,
    135         product_id);
    136     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    137       break;
    138     }
    139     GNUNET_free (categories);
    140     {
    141       const char *eparam;
    142       if (GNUNET_OK !=
    143           TMH_process_quantity_inputs (TMH_VK_QUANTITY,
    144                                        pd.allow_fractional_quantity,
    145                                        quantity_missing,
    146                                        (int64_t) quantity,
    147                                        unit_quantity_missing,
    148                                        unit_quantity,
    149                                        &normalized_quantity,
    150                                        &normalized_quantity_frac,
    151                                        &eparam))
    152       {
    153         TALER_MERCHANTDB_product_details_free (&pd);
    154         GNUNET_break_op (0);
    155         return TALER_MHD_reply_with_error (connection,
    156                                            MHD_HTTP_BAD_REQUEST,
    157                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    158                                            eparam);
    159       }
    160     }
    161     quantity = normalized_quantity;
    162     qs = TMH_db->lock_product (TMH_db->cls,
    163                                mi->settings.id,
    164                                product_id,
    165                                &uuid,
    166                                quantity,
    167                                normalized_quantity_frac,
    168                                GNUNET_TIME_relative_to_timestamp (duration));
    169     TALER_MERCHANTDB_product_details_free (&pd);
    170   }
    171   switch (qs)
    172   {
    173   case GNUNET_DB_STATUS_HARD_ERROR:
    174     GNUNET_break (0);
    175     return TALER_MHD_reply_with_error (
    176       connection,
    177       MHD_HTTP_INTERNAL_SERVER_ERROR,
    178       TALER_EC_GENERIC_DB_STORE_FAILED,
    179       NULL);
    180   case GNUNET_DB_STATUS_SOFT_ERROR:
    181     GNUNET_break (0);
    182     return TALER_MHD_reply_with_error (
    183       connection,
    184       MHD_HTTP_INTERNAL_SERVER_ERROR,
    185       TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    186       "Serialization error for single-statment request");
    187   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    188     GNUNET_break_op (0);
    189     return TALER_MHD_reply_with_error (
    190       connection,
    191       MHD_HTTP_GONE,
    192       TALER_EC_MERCHANT_PRIVATE_POST_PRODUCTS_LOCK_INSUFFICIENT_STOCKS,
    193       product_id);
    194   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    195     return TALER_MHD_reply_static (connection,
    196                                    MHD_HTTP_NO_CONTENT,
    197                                    NULL,
    198                                    NULL,
    199                                    0);
    200   }
    201   GNUNET_assert (0);
    202   return MHD_NO;
    203 }
    204 
    205 
    206 /* end of taler-merchant-httpd_private-patch-products-ID-lock.c */