Added create order endpoint
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
11861b4fb5
commit
e841a9e2fe
@ -1,3 +1,3 @@
|
||||
import { Client } from 'pg';
|
||||
export const client = new Client();
|
||||
import { Pool } from 'pg';
|
||||
export const client = new Pool();
|
||||
client.connect();
|
||||
@ -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…
Reference in New Issue