Compare commits
No commits in common. "fd7d1ffd47aa77631440a4e0713333d21b1529a6" and "bd43f035072a57083ed67f51a728662518e8ba6f" have entirely different histories.
fd7d1ffd47
...
bd43f03507
7
package-lock.json
generated
7
package-lock.json
generated
@ -9,7 +9,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/bourne": "^3.0.0",
|
|
||||||
"@prisma/client": "^6.4.1",
|
"@prisma/client": "^6.4.1",
|
||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
"bulma": "^1.0.3",
|
"bulma": "^1.0.3",
|
||||||
@ -588,12 +587,6 @@
|
|||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@hapi/bourne": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@hapi/hoek": {
|
"node_modules/@hapi/hoek": {
|
||||||
"version": "9.3.0",
|
"version": "9.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/bourne": "^3.0.0",
|
|
||||||
"@prisma/client": "^6.4.1",
|
"@prisma/client": "^6.4.1",
|
||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
"bulma": "^1.0.3",
|
"bulma": "^1.0.3",
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import Bourne from '@hapi/bourne';
|
|
||||||
import Joi from 'joi';
|
|
||||||
|
|
||||||
const validator = Joi.extend((joi) => ({
|
|
||||||
type: 'array',
|
|
||||||
base: Joi.array(),
|
|
||||||
coerce: {
|
|
||||||
from: 'string',
|
|
||||||
method(value, helpers) {
|
|
||||||
if (typeof value !== 'string' || (value[0] !== '[' && !/^\s*\[/.test(value))) {
|
|
||||||
return { value };
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return { value: Bourne.parse(value) };
|
|
||||||
} catch (ignoreErr) {
|
|
||||||
return { value };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default validator;
|
|
@ -16,9 +16,6 @@ import products_schema from './products/products_schema.js';
|
|||||||
import image_route from './image/image.js';
|
import image_route from './image/image.js';
|
||||||
import image_schema from './image/image_schema.js';
|
import image_schema from './image/image_schema.js';
|
||||||
|
|
||||||
import transaction_route from './transaction/transaction.js';
|
|
||||||
import transaction_schema from './transaction/transaction_schema.js';
|
|
||||||
|
|
||||||
// Router base is '/api/v1'
|
// Router base is '/api/v1'
|
||||||
const Router = express.Router({ strict: false });
|
const Router = express.Router({ strict: false });
|
||||||
|
|
||||||
@ -55,9 +52,6 @@ Router.route('/products/describe').get(products_schema);
|
|||||||
Router.route('/image').get(image_route.get).post(image_route.post).patch(image_route.post).delete(image_route.del); // POST and PATCH are handled in 'image_route.post'
|
Router.route('/image').get(image_route.get).post(image_route.post).patch(image_route.post).delete(image_route.del); // POST and PATCH are handled in 'image_route.post'
|
||||||
Router.route('/image/describe').get(image_schema);
|
Router.route('/image/describe').get(image_schema);
|
||||||
|
|
||||||
Router.route('/transaction').get(transaction_route.get).post(transaction_route.post).patch(transaction_route.patch).delete(transaction_route.del);
|
|
||||||
Router.route('/transaction/describe').get(transaction_schema);
|
|
||||||
|
|
||||||
Router.route('/version').get(versionRoute.get);
|
Router.route('/version').get(versionRoute.get);
|
||||||
Router.route('/test').get(testRoute.get);
|
Router.route('/test').get(testRoute.get);
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ async function post(req: Request, res: Response) {
|
|||||||
await db.products
|
await db.products
|
||||||
.create({
|
.create({
|
||||||
data: {
|
data: {
|
||||||
|
id: value.id,
|
||||||
gtin: value.gtin,
|
gtin: value.gtin,
|
||||||
name: value.name,
|
name: value.name,
|
||||||
price: value.price,
|
price: value.price,
|
||||||
|
@ -1,204 +0,0 @@
|
|||||||
import { Request, Response } from 'express';
|
|
||||||
import db, { handlePrismaError } from '../../../../handlers/db.js'; // Database
|
|
||||||
import log from '../../../../handlers/log.js';
|
|
||||||
import { parseDynamicSortBy } from '../../../../helpers/prisma_helpers.js';
|
|
||||||
import { schema_get, schema_post, schema_patch, schema_del } from './transaction_schema.js';
|
|
||||||
import { Prisma } from '@prisma/client';
|
|
||||||
|
|
||||||
// MARK: GET transaction
|
|
||||||
async function get(req: Request, res: Response) {
|
|
||||||
const { error, value } = schema_get.validate(req.query);
|
|
||||||
if (error) {
|
|
||||||
log.api?.debug('GET transaction Error:', req.query, value, error.details[0].message);
|
|
||||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
|
||||||
} else {
|
|
||||||
log.api?.debug('GET transaction Success:', req.query, value);
|
|
||||||
|
|
||||||
if (value.id !== undefined || value.user_id !== undefined) {
|
|
||||||
// get by id or user_id
|
|
||||||
await db
|
|
||||||
.$transaction([
|
|
||||||
// Same query for count and findMany
|
|
||||||
db.transactions.count({
|
|
||||||
where: {
|
|
||||||
OR: [{ id: value.id }, { userId: value.user_id }],
|
|
||||||
paid: value.paid
|
|
||||||
},
|
|
||||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
|
||||||
skip: value.skip,
|
|
||||||
take: value.take
|
|
||||||
}),
|
|
||||||
db.transactions.findMany({
|
|
||||||
where: {
|
|
||||||
OR: [{ id: value.id }, { userId: value.user_id }],
|
|
||||||
paid: value.paid
|
|
||||||
},
|
|
||||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
|
||||||
skip: value.skip,
|
|
||||||
take: value.take
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then(([count, result]) => {
|
|
||||||
if (result.length !== 0) {
|
|
||||||
res.status(200).json({ count, result });
|
|
||||||
} else {
|
|
||||||
res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified transaction' });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
handlePrismaError(err, res, 'GET transaction');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// get all
|
|
||||||
await db
|
|
||||||
.$transaction([
|
|
||||||
// Same query for count and findMany
|
|
||||||
db.transactions.count({
|
|
||||||
where: {
|
|
||||||
paid: value.paid
|
|
||||||
},
|
|
||||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
|
||||||
skip: value.skip,
|
|
||||||
take: value.take
|
|
||||||
}),
|
|
||||||
db.transactions.findMany({
|
|
||||||
where: {
|
|
||||||
paid: value.paid
|
|
||||||
},
|
|
||||||
orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
|
|
||||||
skip: value.skip,
|
|
||||||
take: value.take
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then(([count, result]) => {
|
|
||||||
if (result.length !== 0) {
|
|
||||||
res.status(200).json({ count, result });
|
|
||||||
} else {
|
|
||||||
res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified transaction' });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
handlePrismaError(err, res, 'GET transaction');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: CREATE transaction
|
|
||||||
async function post(req: Request, res: Response) {
|
|
||||||
const { error, value } = schema_post.validate(req.body);
|
|
||||||
if (error) {
|
|
||||||
log.api?.debug('POST transaction Error:', req.body, value, error.details[0].message);
|
|
||||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
|
||||||
} else {
|
|
||||||
log.api?.debug('POST transaction Success:', req.body, value);
|
|
||||||
|
|
||||||
const products: Array<number> = value.products;
|
|
||||||
let total = new Prisma.Decimal(0);
|
|
||||||
const salesData: { productId: number; price: number }[] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Start Prisma transaction
|
|
||||||
await db.$transaction(async (prisma) => {
|
|
||||||
for (let i = 0; i < products.length; i++) {
|
|
||||||
log.api?.debug('Product:', products[i]);
|
|
||||||
const product = await prisma.products.findUnique({
|
|
||||||
where: { id: products[i] },
|
|
||||||
select: { price: true }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (product) {
|
|
||||||
log.api?.debug('Price:', product.price, Number(product.price));
|
|
||||||
//total += Number(product.price);
|
|
||||||
total = total.add(product.price);
|
|
||||||
|
|
||||||
salesData.push({
|
|
||||||
productId: products[i],
|
|
||||||
price: Number(product.price)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
log.api?.debug('Product not found:', products[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.api?.debug('Total:', total.toFixed(2));
|
|
||||||
|
|
||||||
// TODO: Check if user exists
|
|
||||||
|
|
||||||
// Create transaction with sales
|
|
||||||
const transaction = await prisma.transactions.create({
|
|
||||||
data: {
|
|
||||||
userId: value.user_id,
|
|
||||||
total: total,
|
|
||||||
paid: false,
|
|
||||||
sales: {
|
|
||||||
create: salesData
|
|
||||||
}
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(201).json({ status: 'CREATED', message: 'Successfully created transaction', id: transaction.id });
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
handlePrismaError(err, res, 'POST transaction');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: UPDATE transaction
|
|
||||||
async function patch(req: Request, res: Response) {
|
|
||||||
const { error, value } = schema_patch.validate(req.body);
|
|
||||||
if (error) {
|
|
||||||
log.api?.debug('PATCH transaction Error:', req.body, value, error.details[0].message);
|
|
||||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
|
||||||
} else {
|
|
||||||
log.api?.debug('PATCH transaction Success:', req.body, value);
|
|
||||||
await db.transactions
|
|
||||||
.update({
|
|
||||||
where: {
|
|
||||||
id: value.id
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
userId: value.user_id,
|
|
||||||
paid: value.paid
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((result) => {
|
|
||||||
res.status(200).json({ status: 'UPDATED', message: 'Successfully updated transaction', id: result.id });
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
handlePrismaError(err, res, 'PATCH transaction');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: DELETE transaction
|
|
||||||
async function del(req: Request, res: Response) {
|
|
||||||
const { error, value } = schema_del.validate(req.body);
|
|
||||||
if (error) {
|
|
||||||
log.api?.debug('DEL transaction Error:', req.body, value, error.details[0].message);
|
|
||||||
res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
|
|
||||||
} else {
|
|
||||||
log.api?.debug('DEL transaction Success:', req.body, value);
|
|
||||||
await db.transactions
|
|
||||||
.delete({
|
|
||||||
where: {
|
|
||||||
id: value.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((result) => {
|
|
||||||
res.status(200).json({ status: 'DELETED', message: 'Successfully deleted transaction', id: result.id });
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
handlePrismaError(err, res, 'DEL transaction');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default { get, post, patch, del };
|
|
@ -1,58 +0,0 @@
|
|||||||
import { Request, Response } from 'express';
|
|
||||||
//import validator from 'joi'; // DOCS: https://joi.dev/api
|
|
||||||
import validator from '../../../../handlers/validation.js';
|
|
||||||
import { Prisma } from '@prisma/client';
|
|
||||||
|
|
||||||
// MARK: GET transaction
|
|
||||||
const schema_get = validator
|
|
||||||
.object({
|
|
||||||
sort: validator
|
|
||||||
.string()
|
|
||||||
.valid(...Object.keys(Prisma.TransactionsScalarFieldEnum))
|
|
||||||
.default('id'),
|
|
||||||
|
|
||||||
order: validator.string().valid('asc', 'desc').default('asc'),
|
|
||||||
take: validator.number().min(1).max(512),
|
|
||||||
skip: validator.number().min(0),
|
|
||||||
|
|
||||||
id: validator.number().positive().precision(0),
|
|
||||||
user_id: validator.number().positive().precision(0),
|
|
||||||
paid: validator.boolean().note('true-> Only paid / false-> Only unpaid / undefined-> both')
|
|
||||||
})
|
|
||||||
.nand('id', 'user_id'); // Allow id or user_id. not both.
|
|
||||||
|
|
||||||
// MARK: CREATE transaction
|
|
||||||
const schema_post = validator.object({
|
|
||||||
products: validator.array().items(validator.number().positive().precision(0)).required(),
|
|
||||||
user_id: validator.number().positive().precision(0).required(),
|
|
||||||
paid: validator.boolean().default(false)
|
|
||||||
});
|
|
||||||
|
|
||||||
// MARK: UPDATE transaction
|
|
||||||
const schema_patch = validator.object({
|
|
||||||
user_id: validator.number().positive().precision(0).required(),
|
|
||||||
paid: validator.boolean().default(false)
|
|
||||||
});
|
|
||||||
|
|
||||||
// MARK: DELETE transaction
|
|
||||||
const schema_del = validator.object({
|
|
||||||
id: validator.number().positive().precision(0).required()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Describe all schemas
|
|
||||||
const schema_get_desc = schema_get.describe();
|
|
||||||
const schema_post_desc = schema_post.describe();
|
|
||||||
const schema_patch_desc = schema_patch.describe();
|
|
||||||
const schema_del_desc = schema_del.describe();
|
|
||||||
|
|
||||||
// GET route
|
|
||||||
export default async function get(req: Request, res: Response) {
|
|
||||||
res.status(200).json({
|
|
||||||
GET: schema_get_desc,
|
|
||||||
POST: schema_post_desc,
|
|
||||||
PATCH: schema_patch_desc,
|
|
||||||
DELETE: schema_del_desc
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export { schema_get, schema_post, schema_patch, schema_del };
|
|
Loading…
x
Reference in New Issue
Block a user