mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 00:34:06 +02:00
add carts purchase
This commit is contained in:
parent
de4e91db72
commit
c49f0c05d2
@ -2,7 +2,7 @@
|
|||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
email TEXT NOT NULL,
|
email TEXT NOT NULL UNIQUE,
|
||||||
password_hash TEXT NOT NULL,
|
password_hash TEXT NOT NULL,
|
||||||
balance_dkk_cent INTEGER NOT NULL
|
balance_dkk_cent INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
@ -32,6 +32,24 @@ CREATE TABLE IF NOT EXISTS product_prices (
|
|||||||
FOREIGN KEY(product) REFERENCES products(id)
|
FOREIGN KEY(product) REFERENCES products(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS receipts (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
user INTEGER NOT NULL,
|
||||||
|
datetime INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(user) REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS receipt_products (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
receipt INTEGER NOT NULL,
|
||||||
|
product_price INTEGER NOT NULL,
|
||||||
|
amount INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(receipt) REFERENCES receipts(id)
|
||||||
|
FOREIGN KEY(product_price) REFERENCES product_prices(id)
|
||||||
|
);
|
||||||
|
|
||||||
INSERT OR REPLACE INTO users (name, email, password_hash, balance_dkk_cent)
|
INSERT OR REPLACE INTO users (name, email, password_hash, balance_dkk_cent)
|
||||||
VALUES ('User','test@email.com','08ce0220f6d63d85c3ac313e308f4fca35ecfb850baa8ddb924cfab98137b6b18b4a8e027067cb98802757df1337246a0f3aa25c44c2b788517a871086419dcf',10000);
|
VALUES ('User','test@email.com','08ce0220f6d63d85c3ac313e308f4fca35ecfb850baa8ddb924cfab98137b6b18b4a8e027067cb98802757df1337246a0f3aa25c44c2b788517a871086419dcf',10000);
|
||||||
|
|
||||||
|
@ -25,12 +25,50 @@ void route_post_carts_purchase(HttpCtx* ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("product_id\tamount\n");
|
size_t item_amount = req.items.size;
|
||||||
for (size_t i = 0; i < req.items.size; ++i) {
|
|
||||||
printf("%ld\t\t%ld\n",
|
ProductPriceVec prices;
|
||||||
req.items.data[i].product_id,
|
product_price_vec_construct(&prices);
|
||||||
req.items.data[i].amount);
|
|
||||||
|
for (size_t i = 0; i < item_amount; ++i) {
|
||||||
|
ProductPrice price;
|
||||||
|
DbRes db_res = db_product_price_of_product(
|
||||||
|
cx->db, &price, req.items.data[i].product_id);
|
||||||
|
if (db_res != DbRes_Ok) {
|
||||||
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
product_price_vec_push(&prices, price);
|
||||||
}
|
}
|
||||||
|
|
||||||
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
Receipt receipt = {
|
||||||
|
.id = 0,
|
||||||
|
.user_id = session->user_id,
|
||||||
|
.timestamp = NULL,
|
||||||
|
.products = (ReceiptProductVec) { 0 },
|
||||||
|
};
|
||||||
|
receipt_product_vec_construct(&receipt.products);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < item_amount; ++i) {
|
||||||
|
receipt_product_vec_push(&receipt.products,
|
||||||
|
(ReceiptProduct) {
|
||||||
|
.id = 0,
|
||||||
|
.receipt_id = 0,
|
||||||
|
.product_price_id = prices.data[i].id,
|
||||||
|
.amount = req.items.data[i].amount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t receipt_id;
|
||||||
|
DbRes db_res = db_receipt_insert(cx->db, &receipt, &receipt_id);
|
||||||
|
if (db_res != DbRes_Ok) {
|
||||||
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RESPOND_JSON(ctx, 200, "{\"ok\":true,\"receipt_id\":%ld}", receipt_id);
|
||||||
|
|
||||||
|
l0_return:
|
||||||
|
receipt_destroy(&receipt);
|
||||||
|
product_price_vec_destroy(&prices);
|
||||||
}
|
}
|
||||||
|
@ -27,21 +27,17 @@ void route_post_users_register(HttpCtx* ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ids ids;
|
bool email_used;
|
||||||
ids_construct(&ids);
|
if (db_user_with_email_exists(cx->db, &email_used, req.email) != DbRes_Ok) {
|
||||||
if (db_users_with_email(cx->db, &ids, req.email) != DbRes_Ok) {
|
|
||||||
RESPOND_SERVER_ERROR(ctx);
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
ids_destroy(&ids);
|
|
||||||
users_register_req_destroy(&req);
|
users_register_req_destroy(&req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ids.size > 0) {
|
if (email_used) {
|
||||||
RESPOND_BAD_REQUEST(ctx, "email in use");
|
RESPOND_BAD_REQUEST(ctx, "email in use");
|
||||||
ids_destroy(&ids);
|
|
||||||
users_register_req_destroy(&req);
|
users_register_req_destroy(&req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ids_destroy(&ids);
|
|
||||||
|
|
||||||
char* password_hash = str_hash(req.password);
|
char* password_hash = str_hash(req.password);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "../collections/collection.h"
|
#include "../collections/collection.h"
|
||||||
#include "../models/models.h"
|
#include "../models/models.h"
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
DEFINE_VEC(int64_t, Ids, ids)
|
DEFINE_VEC(int64_t, Ids, ids)
|
||||||
@ -20,11 +21,19 @@ DbRes db_user_insert(Db* db, const User* user);
|
|||||||
/// `user` field is an out parameter.
|
/// `user` field is an out parameter.
|
||||||
DbRes db_user_with_id(Db* db, User* user, int64_t id);
|
DbRes db_user_with_id(Db* db, User* user, int64_t id);
|
||||||
|
|
||||||
/// Expects `ids` to be constructed.
|
DbRes db_user_with_email_exists(Db* db, bool* exists, const char* email);
|
||||||
DbRes db_users_with_email(Db* db, Ids* ids, const char* email);
|
|
||||||
|
|
||||||
/// `user` is an out parameter.
|
/// `user` is an out parameter.
|
||||||
DbRes db_user_with_email(Db* db, User* user, const char* email);
|
DbRes db_user_with_email(Db* db, User* user, const char* email);
|
||||||
|
|
||||||
/// Expects `vec` to be constructed.
|
/// Expects `vec` to be constructed.
|
||||||
DbRes db_product_all(Db* db, ProductVec* vec);
|
DbRes db_product_all(Db* db, ProductVec* vec);
|
||||||
|
|
||||||
|
/// `product_price` is an out parameter.
|
||||||
|
DbRes db_product_price_of_product(
|
||||||
|
Db* db, ProductPrice* product_price, int64_t product_id);
|
||||||
|
|
||||||
|
/// `receipt.id`, `receipt.timestamp` and `receipt.products[i].id`
|
||||||
|
/// are ignored.
|
||||||
|
/// `id` is an out parameter.
|
||||||
|
DbRes db_receipt_insert(Db* db, const Receipt* receipt, int64_t* id);
|
||||||
|
@ -7,6 +7,13 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define REPORT_SQLITE3_ERROR() \
|
||||||
|
fprintf(stderr, \
|
||||||
|
"error: %s\n at %s:%d\n", \
|
||||||
|
sqlite3_errmsg(connection), \
|
||||||
|
__func__, \
|
||||||
|
__LINE__)
|
||||||
|
|
||||||
static inline char* get_str_safe(sqlite3_stmt* stmt, int col)
|
static inline char* get_str_safe(sqlite3_stmt* stmt, int col)
|
||||||
{
|
{
|
||||||
const char* val = (const char*)sqlite3_column_text(stmt, col);
|
const char* val = (const char*)sqlite3_column_text(stmt, col);
|
||||||
@ -146,10 +153,8 @@ l0_return:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
DbRes db_users_with_email(Db* db, Ids* ids, const char* email)
|
DbRes db_user_with_email_exists(Db* db, bool* exists, const char* email)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(User) == 40, "model has changed");
|
|
||||||
|
|
||||||
sqlite3* connection;
|
sqlite3* connection;
|
||||||
CONNECT;
|
CONNECT;
|
||||||
DbRes res;
|
DbRes res;
|
||||||
@ -160,9 +165,9 @@ DbRes db_users_with_email(Db* db, Ids* ids, const char* email)
|
|||||||
connection, "SELECT id FROM users WHERE email = ?", -1, &stmt, NULL);
|
connection, "SELECT id FROM users WHERE email = ?", -1, &stmt, NULL);
|
||||||
sqlite3_bind_text(stmt, 1, email, -1, NULL);
|
sqlite3_bind_text(stmt, 1, email, -1, NULL);
|
||||||
|
|
||||||
while ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) {
|
*exists = false;
|
||||||
int64_t id = GET_INT(0);
|
if ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||||
ids_push(ids, id);
|
*exists = true;
|
||||||
}
|
}
|
||||||
if (sqlite_res != SQLITE_DONE) {
|
if (sqlite_res != SQLITE_DONE) {
|
||||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||||
@ -194,11 +199,7 @@ DbRes db_user_with_email(Db* db, User* user, const char* email)
|
|||||||
&stmt,
|
&stmt,
|
||||||
NULL);
|
NULL);
|
||||||
if (prepare_res != SQLITE_OK) {
|
if (prepare_res != SQLITE_OK) {
|
||||||
fprintf(stderr,
|
REPORT_SQLITE3_ERROR();
|
||||||
"error: %s\n at %s:%d\n",
|
|
||||||
sqlite3_errmsg(connection),
|
|
||||||
__func__,
|
|
||||||
__LINE__);
|
|
||||||
res = DbRes_Error;
|
res = DbRes_Error;
|
||||||
goto l0_return;
|
goto l0_return;
|
||||||
}
|
}
|
||||||
@ -209,12 +210,7 @@ DbRes db_user_with_email(Db* db, User* user, const char* email)
|
|||||||
res = DbRes_NotFound;
|
res = DbRes_NotFound;
|
||||||
goto l0_return;
|
goto l0_return;
|
||||||
} else if (step_res != SQLITE_ROW) {
|
} else if (step_res != SQLITE_ROW) {
|
||||||
printf("step_res = %d, email = '%s'\n", step_res, email);
|
REPORT_SQLITE3_ERROR();
|
||||||
fprintf(stderr,
|
|
||||||
"error: %s\n at %s:%d\n",
|
|
||||||
sqlite3_errmsg(connection),
|
|
||||||
__func__,
|
|
||||||
__LINE__);
|
|
||||||
res = DbRes_Error;
|
res = DbRes_Error;
|
||||||
goto l0_return;
|
goto l0_return;
|
||||||
}
|
}
|
||||||
@ -279,3 +275,212 @@ l0_return:
|
|||||||
DISCONNECT;
|
DISCONNECT;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline DbRes get_product_price_from_product_id(
|
||||||
|
sqlite3* connection, int64_t product_id, int64_t* price)
|
||||||
|
{
|
||||||
|
DbRes res;
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"SELECT price_dkk_cent FROM products WHERE id = ?",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int64(stmt, 1, product_id);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res == SQLITE_DONE) {
|
||||||
|
res = DbRes_NotFound;
|
||||||
|
goto l0_return;
|
||||||
|
} else if (step_res != SQLITE_ROW) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
*price = GET_INT(0);
|
||||||
|
|
||||||
|
res = DbRes_Ok;
|
||||||
|
l0_return:
|
||||||
|
if (stmt)
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline DbRes insert_product_price(sqlite3* connection,
|
||||||
|
ProductPrice* product_price,
|
||||||
|
int64_t product_id,
|
||||||
|
int64_t price)
|
||||||
|
{
|
||||||
|
DbRes res;
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"INSERT INTO product_prices (product, price_dkk_cent) "
|
||||||
|
"VALUES (?, ?)",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_bind_int64(stmt, 1, product_id);
|
||||||
|
sqlite3_bind_int64(stmt, 2, price);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res != SQLITE_DONE) {
|
||||||
|
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t id = sqlite3_last_insert_rowid(connection);
|
||||||
|
*product_price = (ProductPrice) {
|
||||||
|
.id = id,
|
||||||
|
.product_id = product_id,
|
||||||
|
.price_dkk_cent = price,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = DbRes_Ok;
|
||||||
|
l0_return:
|
||||||
|
if (stmt)
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DbRes db_product_price_of_product(
|
||||||
|
Db* db, ProductPrice* product_price, int64_t product_id)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(ProductPrice) == 24, "model has changed");
|
||||||
|
|
||||||
|
sqlite3* connection;
|
||||||
|
CONNECT;
|
||||||
|
DbRes res;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
int prepare_res;
|
||||||
|
|
||||||
|
int64_t current_price;
|
||||||
|
res = get_product_price_from_product_id(
|
||||||
|
connection, product_id, ¤t_price);
|
||||||
|
if (res != DbRes_Ok) {
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find maybe existing product price
|
||||||
|
prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"SELECT id FROM product_prices"
|
||||||
|
" WHERE product = ? AND price_dkk_cent = ?",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int64(stmt, 1, product_id);
|
||||||
|
sqlite3_bind_int64(stmt, 2, current_price);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res == SQLITE_ROW) {
|
||||||
|
*product_price = (ProductPrice) {
|
||||||
|
.id = GET_INT(0),
|
||||||
|
.product_id = product_id,
|
||||||
|
.price_dkk_cent = current_price,
|
||||||
|
};
|
||||||
|
} else if (step_res == SQLITE_DONE) {
|
||||||
|
insert_product_price(
|
||||||
|
connection, product_price, product_id, current_price);
|
||||||
|
} else {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = DbRes_Ok;
|
||||||
|
l0_return:
|
||||||
|
if (stmt)
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
DISCONNECT;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DbRes db_receipt_insert(Db* db, const Receipt* receipt, int64_t* id)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Receipt) == 48, "model has changed");
|
||||||
|
static_assert(sizeof(ReceiptProduct) == 32, "model has changed");
|
||||||
|
|
||||||
|
sqlite3* connection;
|
||||||
|
CONNECT;
|
||||||
|
DbRes res;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"INSERT INTO receipts (user, datetime) "
|
||||||
|
"VALUES (?, unixepoch('now'))",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_bind_int64(stmt, 1, receipt->user_id);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res != SQLITE_DONE) {
|
||||||
|
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t receipt_id = sqlite3_last_insert_rowid(connection);
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
*id = receipt_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < receipt->products.size; ++i) {
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"INSERT INTO receipt_products (receipt, product_price, amount) "
|
||||||
|
"VALUES (?, ?, ?)",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_bind_int64(stmt, 1, receipt_id);
|
||||||
|
sqlite3_bind_int64(stmt, 2, receipt->products.data[i].product_price_id);
|
||||||
|
sqlite3_bind_int64(stmt, 3, receipt->products.data[i].amount);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res != SQLITE_DONE) {
|
||||||
|
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = DbRes_Ok;
|
||||||
|
l0_return:
|
||||||
|
if (stmt)
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
DISCONNECT;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@ -39,6 +39,20 @@ void product_price_destroy(ProductPrice* m)
|
|||||||
(void)m;
|
(void)m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void receipt_product_destroy(ReceiptProduct* m)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(ReceiptProduct) == 32, "model has changed");
|
||||||
|
|
||||||
|
(void)m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void receipt_destroy(Receipt* m)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Receipt) == 48, "model has changed");
|
||||||
|
|
||||||
|
(void)m;
|
||||||
|
}
|
||||||
|
|
||||||
void users_register_req_destroy(UsersRegisterReq* model)
|
void users_register_req_destroy(UsersRegisterReq* model)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(UsersRegisterReq) == 24, "model has changed");
|
static_assert(sizeof(UsersRegisterReq) == 24, "model has changed");
|
||||||
@ -156,6 +170,43 @@ char* product_price_to_json_string(const ProductPrice* m)
|
|||||||
string_destroy(&string);
|
string_destroy(&string);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
char* receipt_to_json_string(const Receipt* m)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Receipt) == 48, "model has changed");
|
||||||
|
|
||||||
|
String string;
|
||||||
|
string_construct(&string);
|
||||||
|
string_pushf(&string,
|
||||||
|
"{"
|
||||||
|
"\"id\":%ld,"
|
||||||
|
"\"user_id\":%ld,"
|
||||||
|
"\"timestamp\":\"%s\","
|
||||||
|
"\"products\":[",
|
||||||
|
m->id,
|
||||||
|
m->user_id,
|
||||||
|
m->timestamp);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m->products.size; ++i) {
|
||||||
|
if (i != 0) {
|
||||||
|
string_pushf(&string, ",");
|
||||||
|
}
|
||||||
|
string_pushf(&string,
|
||||||
|
"{"
|
||||||
|
"\"id\":%ld,"
|
||||||
|
"\"receipt_id\":%ld,"
|
||||||
|
"\"product_price_id\":%ld,"
|
||||||
|
"\"amount\":%ld"
|
||||||
|
"}",
|
||||||
|
m->products.data[i].id,
|
||||||
|
m->products.data[i].receipt_id,
|
||||||
|
m->products.data[i].product_price_id,
|
||||||
|
m->products.data[i].amount);
|
||||||
|
}
|
||||||
|
string_pushf(&string, "]}");
|
||||||
|
char* result = string_copy(&string);
|
||||||
|
string_destroy(&string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
char* users_register_req_to_json(const UsersRegisterReq* m)
|
char* users_register_req_to_json(const UsersRegisterReq* m)
|
||||||
{
|
{
|
||||||
@ -321,6 +372,13 @@ int product_price_from_json(ProductPrice* m, const JsonValue* json)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int receipt_from_json(Receipt* m, const JsonValue* json)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Receipt) == 48, "model has changed");
|
||||||
|
|
||||||
|
PANIC("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
int users_register_req_from_json(UsersRegisterReq* m, const JsonValue* json)
|
int users_register_req_from_json(UsersRegisterReq* m, const JsonValue* json)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(UsersRegisterReq) == 24, "model has changed");
|
static_assert(sizeof(UsersRegisterReq) == 24, "model has changed");
|
||||||
@ -396,4 +454,6 @@ int carts_purchase_req_from_json(CartsPurchaseReq* m, const JsonValue* json)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_VEC_IMPL(ProductPrice, ProductPriceVec, product_price_vec, )
|
||||||
|
DEFINE_VEC_IMPL(ReceiptProduct, ReceiptProductVec, receipt_product_vec, )
|
||||||
DEFINE_VEC_IMPL(CartsItem, CartsItemVec, carts_item_vec, )
|
DEFINE_VEC_IMPL(CartsItem, CartsItemVec, carts_item_vec, )
|
||||||
|
@ -32,10 +32,30 @@ typedef struct {
|
|||||||
int64_t price_dkk_cent;
|
int64_t price_dkk_cent;
|
||||||
} ProductPrice;
|
} ProductPrice;
|
||||||
|
|
||||||
|
DECLARE_VEC_TYPE(ProductPrice, ProductPriceVec, product_price_vec, )
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t id;
|
||||||
|
int64_t receipt_id;
|
||||||
|
int64_t product_price_id;
|
||||||
|
int64_t amount;
|
||||||
|
} ReceiptProduct;
|
||||||
|
|
||||||
|
DECLARE_VEC_TYPE(ReceiptProduct, ReceiptProductVec, receipt_product_vec, )
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t id;
|
||||||
|
int64_t user_id;
|
||||||
|
char* timestamp;
|
||||||
|
ReceiptProductVec products;
|
||||||
|
} Receipt;
|
||||||
|
|
||||||
void user_destroy(User* model);
|
void user_destroy(User* model);
|
||||||
void coord_destroy(Coord* model);
|
void coord_destroy(Coord* model);
|
||||||
void product_destroy(Product* model);
|
void product_destroy(Product* model);
|
||||||
void product_price_destroy(ProductPrice* model);
|
void product_price_destroy(ProductPrice* model);
|
||||||
|
void receipt_product_destroy(ReceiptProduct* model);
|
||||||
|
void receipt_destroy(Receipt* model);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ DEFINE_MODEL_JSON(User, user)
|
|||||||
DEFINE_MODEL_JSON(Coord, coord)
|
DEFINE_MODEL_JSON(Coord, coord)
|
||||||
DEFINE_MODEL_JSON(Product, product)
|
DEFINE_MODEL_JSON(Product, product)
|
||||||
DEFINE_MODEL_JSON(ProductPrice, product_price)
|
DEFINE_MODEL_JSON(ProductPrice, product_price)
|
||||||
|
DEFINE_MODEL_JSON(Receipt, receipt)
|
||||||
|
|
||||||
DEFINE_MODEL_JSON(UsersRegisterReq, users_register_req)
|
DEFINE_MODEL_JSON(UsersRegisterReq, users_register_req)
|
||||||
DEFINE_MODEL_JSON(SessionsLoginReq, sessions_login_req)
|
DEFINE_MODEL_JSON(SessionsLoginReq, sessions_login_req)
|
||||||
|
@ -70,12 +70,15 @@ async function testCarts(t: Deno.TestContext, token: string) {
|
|||||||
items: [
|
items: [
|
||||||
{ product_id: 1, amount: 2 },
|
{ product_id: 1, amount: 2 },
|
||||||
{ product_id: 2, amount: 5 },
|
{ product_id: 2, amount: 5 },
|
||||||
|
{ product_id: 2, amount: 5 },
|
||||||
|
{ product_id: 2, amount: 5 },
|
||||||
|
{ product_id: 2, amount: 5 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ "Session-Token": token },
|
{ "Session-Token": token },
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(res, { ok: true });
|
assertEquals(res.ok, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user