Line data Source code
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/do_expire_locks.h"
30 : #include "merchant-database/insert_inventory_lock.h"
31 : #include "merchant-database/get_product.h"
32 :
33 :
34 : enum MHD_Result
35 14 : TMH_private_post_products_ID_lock (
36 : const struct TMH_RequestHandler *rh,
37 : struct MHD_Connection *connection,
38 : struct TMH_HandlerContext *hc)
39 : {
40 14 : struct TMH_MerchantInstance *mi = hc->instance;
41 14 : 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 14 : const char *unit_quantity = NULL;
48 14 : bool unit_quantity_missing = true;
49 : struct GNUNET_TIME_Relative duration;
50 : struct GNUNET_JSON_Specification spec[] = {
51 14 : GNUNET_JSON_spec_string ("lock_uuid",
52 : &uuids),
53 14 : GNUNET_JSON_spec_relative_time ("duration",
54 : &duration),
55 14 : GNUNET_JSON_spec_mark_optional (
56 : GNUNET_JSON_spec_uint64 ("quantity",
57 : &quantity),
58 : &quantity_missing),
59 14 : GNUNET_JSON_spec_mark_optional (
60 : GNUNET_JSON_spec_string ("unit_quantity",
61 : &unit_quantity),
62 : &unit_quantity_missing),
63 14 : GNUNET_JSON_spec_end ()
64 : };
65 :
66 14 : GNUNET_assert (NULL != mi);
67 14 : GNUNET_assert (NULL != product_id);
68 : {
69 : enum GNUNET_GenericReturnValue res;
70 :
71 14 : res = TALER_MHD_parse_json_data (connection,
72 14 : hc->request_body,
73 : spec);
74 14 : if (GNUNET_OK != res)
75 : return (GNUNET_NO == res)
76 : ? MHD_YES
77 0 : : MHD_NO;
78 : }
79 14 : TMH_uuid_from_string (uuids,
80 : &uuid);
81 14 : TALER_MERCHANTDB_do_expire_locks (TMH_db);
82 : {
83 14 : struct TALER_MERCHANTDB_ProductDetails pd = { 0 };
84 : size_t num_categories;
85 : uint64_t *categories;
86 14 : uint64_t normalized_quantity = 0;
87 14 : uint32_t normalized_quantity_frac = 0;
88 :
89 14 : if (quantity_missing && unit_quantity_missing)
90 : {
91 0 : quantity = 1;
92 0 : quantity_missing = false;
93 : }
94 14 : else if ( (! quantity_missing) &&
95 0 : (quantity > (uint64_t) INT64_MAX) )
96 : {
97 0 : GNUNET_break_op (0);
98 4 : return TALER_MHD_reply_with_error (connection,
99 : MHD_HTTP_BAD_REQUEST,
100 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
101 : "quantity");
102 : }
103 :
104 14 : qs = TALER_MERCHANTDB_get_product (TMH_db,
105 14 : mi->settings.id,
106 : product_id,
107 : &pd,
108 : &num_categories,
109 : &categories);
110 14 : switch (qs)
111 : {
112 0 : case GNUNET_DB_STATUS_HARD_ERROR:
113 0 : GNUNET_break (0);
114 0 : TALER_MERCHANTDB_product_details_free (&pd);
115 0 : GNUNET_free (categories);
116 0 : return TALER_MHD_reply_with_error (
117 : connection,
118 : MHD_HTTP_INTERNAL_SERVER_ERROR,
119 : TALER_EC_GENERIC_DB_FETCH_FAILED,
120 : "get_product");
121 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
122 0 : GNUNET_break (0);
123 0 : TALER_MERCHANTDB_product_details_free (&pd);
124 0 : GNUNET_free (categories);
125 0 : return TALER_MHD_reply_with_error (
126 : connection,
127 : MHD_HTTP_INTERNAL_SERVER_ERROR,
128 : TALER_EC_GENERIC_DB_SOFT_FAILURE,
129 : "get_product");
130 2 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
131 2 : GNUNET_break_op (0);
132 2 : TALER_MERCHANTDB_product_details_free (&pd);
133 2 : GNUNET_free (categories);
134 2 : return TALER_MHD_reply_with_error (
135 : connection,
136 : MHD_HTTP_NOT_FOUND,
137 : TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN,
138 : product_id);
139 12 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
140 12 : break;
141 : }
142 12 : GNUNET_free (categories);
143 : {
144 : const char *eparam;
145 12 : if (GNUNET_OK !=
146 12 : TALER_MERCHANT_vk_process_quantity_inputs (
147 : TALER_MERCHANT_VK_QUANTITY,
148 12 : 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 2 : TALER_MERCHANTDB_product_details_free (&pd);
158 2 : GNUNET_break_op (0);
159 2 : return TALER_MHD_reply_with_error (connection,
160 : MHD_HTTP_BAD_REQUEST,
161 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
162 : eparam);
163 : }
164 : }
165 10 : quantity = normalized_quantity;
166 10 : qs = TALER_MERCHANTDB_insert_inventory_lock (TMH_db,
167 10 : mi->settings.id,
168 : product_id,
169 : &uuid,
170 : quantity,
171 : normalized_quantity_frac,
172 : GNUNET_TIME_relative_to_timestamp (duration));
173 10 : TALER_MERCHANTDB_product_details_free (&pd);
174 : }
175 10 : switch (qs)
176 : {
177 0 : case GNUNET_DB_STATUS_HARD_ERROR:
178 0 : GNUNET_break (0);
179 0 : return TALER_MHD_reply_with_error (
180 : connection,
181 : MHD_HTTP_INTERNAL_SERVER_ERROR,
182 : TALER_EC_GENERIC_DB_STORE_FAILED,
183 : NULL);
184 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
185 0 : GNUNET_break (0);
186 0 : 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 3 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
192 3 : GNUNET_break_op (0);
193 3 : 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 7 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
199 7 : return TALER_MHD_reply_static (connection,
200 : MHD_HTTP_NO_CONTENT,
201 : NULL,
202 : NULL,
203 : 0);
204 : }
205 0 : GNUNET_assert (0);
206 : return MHD_NO;
207 : }
208 :
209 :
210 : /* end of taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.c */
|