Added create order endpoint
continuous-integration/drone/push Build is passing Details

main
Filip Borum Poulsen 3 years ago
parent 11861b4fb5
commit e841a9e2fe

@ -1,3 +1,3 @@
import { Client } from 'pg'; import { Pool } from 'pg';
export const client = new Client(); export const client = new Pool();
client.connect(); client.connect();

@ -10,5 +10,5 @@ export interface UserTokenData {
} }
export interface AuthedRequest extends Request { export interface AuthedRequest extends Request {
user?: UserTokenData | JwtPayload | string | undefined user?: UserTokenData
} }

@ -7,11 +7,13 @@ import register from "./register"
import center from "./center"; import center from "./center";
import trainer from "./trainer"; import trainer from "./trainer";
import timeslot from "./timeslot"; import timeslot from "./timeslot";
import order from "./order";
router.use(login); router.use(login);
router.use(register); router.use(register);
router.use(center); router.use(center);
router.use(trainer); router.use(trainer);
router.use(timeslot); router.use(timeslot);
router.use(order);
export default router; export default router;

@ -0,0 +1,156 @@
import express, { Router, Request, Response, NextFunction } from "express";
import Joi from "joi"
import dayjs from "dayjs"
import isoWeek from "dayjs/plugin/isoWeek"
import utc from "dayjs/plugin/utc"
import { client, client as pool } from "../db";
import { DatabaseError } from "pg";
import Trainer from "../interfaces/trainer";
import { ReservedTimeslots, Timeslot, WeeklyTimeslot } from "../interfaces/timeslot";
import { idSchema, timeSchema } from "../schemas";
import { UserAuth } from "../middlewares/auth";
import { AuthedRequest } from "../interfaces/auth";
dayjs.extend(isoWeek)
dayjs.extend(utc)
const router: Router = express.Router();
const orderSchema = Joi.object({
trainer: idSchema.required(),
startDate: Joi.date().required(),
endDate: Joi.date().required()
});
interface DatabaseResult {
trainer: Trainer
timeslots: WeeklyTimeslot[]
reserved_timeslots: ReservedTimeslots[]
}
interface OrderBody {
trainer: number
startDate: Date
endDate: Date
}
interface TimeslotValidQueryResult {
weekly_timeslot_available: boolean
time_already_reserved: boolean
}
router.post("/order", UserAuth, async (req: AuthedRequest, res: Response) => {
try {
const client = await pool.connect();
try {
const validation = orderSchema.validate(req.body, { abortEarly: false });
if (validation.error !== undefined) {
return res.status(400).send(validation.error.details);
}
const orderBody: OrderBody = validation.value;
const startDate: dayjs.Dayjs = dayjs(orderBody.startDate).utcOffset(0);
const endDate: dayjs.Dayjs = dayjs(orderBody.endDate).utcOffset(0);
const startTime: string = `${startDate.hour()}:${startDate.minute()}`;
const endTime: string = `${endDate.hour()}:${endDate.minute()}`;
const weekday = startDate.isoWeekday();
await client.query("BEGIN");
const timeslotValidQuery = await client.query(`
select
EXISTS(
SELECT 1 FROM weekly_timeslots
WHERE
trainer_id = $1
AND day_of_week = $2
AND start_time = $3
AND end_time = $4
) as weekly_timeslot_available,
EXISTS(
SELECT 1 FROM public.reserved_timeslots
WHERE (
(start_time between $5 AND $6
OR end_time between $5 AND $6))
AND trainer_id = $1
) as time_already_reserved;
`, [
orderBody.trainer,
weekday,
startTime,
endTime,
orderBody.startDate,
orderBody.endDate
]);
const timeslotValidQueryResult: TimeslotValidQueryResult = timeslotValidQuery.rows[0];
if (timeslotValidQueryResult.time_already_reserved || !timeslotValidQueryResult.weekly_timeslot_available)
return res.status(400).send([{
message: "timeslot was not found",
path: [
"startDate"
],
type: "startDate.invalid"
}]);
const priceQuery = await client.query(`
SELECT hourly_price FROM trainers WHERE id = $1;
`, [
orderBody.trainer
]);
const hourlyPrice = priceQuery.rows[0].hourly_price;
const hours = endDate.diff(startDate, "hours", true);
const price = Math.ceil(hours * hourlyPrice);
const insertQuery = await client.query(`
WITH inserted_reserved_timeslot AS (
INSERT INTO reserved_timeslots (trainer_id, start_time, end_time)
VALUES ($1, $2, $3)
RETURNING *
)
INSERT INTO orders (timeslot_id, user_id, order_status, price)
select id, $4, 'Processing', $5
FROM inserted_reserved_timeslot
RETURNING id;
`, [
orderBody.trainer,
orderBody.startDate,
orderBody.endDate,
req.user?.userId,
price
]);
const insertedData = insertQuery.rows[0];
await client.query("COMMIT");
return res.status(200).send({
id: insertedData.id,
trainerId: orderBody.trainer,
startDate: orderBody.startDate,
endDate: orderBody.endDate,
price
});
} catch (error: DatabaseError | Error | any) {
await client.query("ROLLBACK");
console.error(error);
return res.sendStatus(500);
}
finally {
client.release();
}
} catch (error: DatabaseError | Error | any) {
console.error(error);
return res.sendStatus(500);
}
})
export default router;
Loading…
Cancel
Save