import orderLogs, { IOrderLogs, orderLogger } from './order.logs'; import { formatString } from '../../utils/Strings'; import { HttpCodes } from '../../config/Errors'; import { ErrorResponseC, SuccessResponseC } from '../services.response'; import { db } from '../../settings'; import { ResultSetHeader, RowDataPacket } from 'mysql2'; import { EnrollmentServices } from '../enrollment/enrollment.service'; import courseLogs from '../course/course.logs'; export class OrderServices { /** * @description Create an order * @param course_id - Number * @param pack_id - Number * @param school_id - Number * @param price - Number * @param status - String * @param note - String * @returns ResponseT */ static createSchoolOrder = async ( course_id: number, pack_id: number, school_id: number, price: number, status: string, note: string ): Promise => { try { // check if the status is active const courseStatusQuery = 'SELECT status FROM courses WHERE course_id = ?'; const [courseStatus] = await db.query( courseStatusQuery, [course_id] ); if (courseStatus.length === 0) { const msg = formatString(courseLogs.COURSE_ERROR_NOT_FOUND.message, { course_id, }); orderLogger.error(msg); return new ErrorResponseC( courseLogs.COURSE_ERROR_NOT_FOUND.type, HttpCodes.NotFound.code, msg ); } if (courseStatus[0].status !== 'active') { const msg = formatString(courseLogs.COURSE_NOT_ACTIVE.message, { course_id, }); orderLogger.error(msg); return new ErrorResponseC( courseLogs.COURSE_NOT_ACTIVE.type, HttpCodes.BadRequest.code, msg ); } // check if there is already an order for the course and school const orderExistsQuery = 'SELECT * FROM orders WHERE course_id = ? AND school_id = ?'; const [orderExists] = await db.query(orderExistsQuery, [ course_id, school_id, ]); if (orderExists.length > 0) { const msg = formatString(orderLogs.ORDER_ERROR_INVALID_INPUT.message, { input: `Order ${orderExists[0].order_id} already exists for the course and school`, }); orderLogger.error(msg); return new ErrorResponseC( orderLogs.ORDER_ERROR_INVALID_INPUT.type, HttpCodes.BadRequest.code, msg ); } const createdAt = new Date(); const updatedAt = createdAt; const sqlInsertQuery = 'INSERT INTO orders (course_id, pack_id, school_id, price, status, note, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'; const result: any = await db.query(sqlInsertQuery, [ course_id, pack_id, school_id, price, status, note, createdAt, updatedAt, ]); const orderId = result[0].insertId; const order: OrderI = { order_id: orderId, course_id, pack_id, school_id, price, status, note, }; const resp: ICode = orderLogs.CREATE_ORDER_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, order, msg, HttpCodes.Created.code ); } catch (err) { const msg = formatString(orderLogs.CREATE_ORDER_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.CREATE_ORDER_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; /** * @description Create an order * @param course_id - Number * @param pack_id - Number * @param teacher_id - Number * @param price - Number * @param status - String * @param note - String * @returns ResponseT */ static createTeacherOrder = async ( course_id: number, pack_id: number, teacher_id: number, price: number, status: string, note: string ): Promise => { try { // check if the status is active const courseStatusQuery = 'SELECT status FROM courses WHERE course_id = ?'; const [courseStatus] = await db.query( courseStatusQuery, [course_id] ); if (courseStatus.length === 0) { const msg = formatString(courseLogs.COURSE_ERROR_NOT_FOUND.message, { course_id, }); orderLogger.error(msg); return new ErrorResponseC( courseLogs.COURSE_ERROR_NOT_FOUND.type, HttpCodes.NotFound.code, msg ); } if (courseStatus[0].status !== 'active') { const msg = formatString(courseLogs.COURSE_NOT_ACTIVE.message, { course_id, }); orderLogger.error(msg); return new ErrorResponseC( courseLogs.COURSE_NOT_ACTIVE.type, HttpCodes.BadRequest.code, msg ); } // check if there is already an order for the course and teacher const orderExistsQuery = 'SELECT * FROM orders WHERE course_id = ? AND teacher_id = ?'; const [orderExists] = await db.query(orderExistsQuery, [ course_id, teacher_id, ]); if (orderExists.length > 0) { const msg = formatString(orderLogs.ORDER_ERROR_INVALID_INPUT.message, { error: 'Order already exists for the course and teacher', }); orderLogger.error(msg); return new ErrorResponseC( orderLogs.ORDER_ERROR_INVALID_INPUT.type, HttpCodes.BadRequest.code, msg ); } const createdAt = new Date(); const updatedAt = createdAt; const sqlInsertQuery = 'INSERT INTO orders (course_id, pack_id, teacher_id, price, status, note, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'; const result: any = await db.query(sqlInsertQuery, [ course_id, pack_id, teacher_id, price, status, note, createdAt, updatedAt, ]); const orderId = result[0].insertId; // create enrollment const enrollmentResult = await EnrollmentServices.createEnrollment( course_id, teacher_id ); if (enrollmentResult instanceof ErrorResponseC) { // remove order if enrollment creation fails const sqlDeleteQuery = 'DELETE FROM orders WHERE order_id = ?'; await db.query(sqlDeleteQuery, [orderId]); return enrollmentResult; } const order: OrderI = { order_id: orderId, course_id, pack_id, teacher_id, price, status, note, }; const resp: ICode = orderLogs.CREATE_ORDER_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, order, msg, HttpCodes.Created.code ); } catch (err) { const msg = formatString(orderLogs.CREATE_ORDER_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.CREATE_ORDER_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; /** * @description Delete an order * @param orderId - Number * @returns ResponseT */ static deleteOrder = async (orderId: number): Promise => { try { // order is associated with teacher, delete enrollment const sqlSelectQuery = 'SELECT teacher_id, course_id FROM orders WHERE order_id = ?'; const [order] = await db.query(sqlSelectQuery, [orderId]); if (order.length > 0) { // const { teacher_id, course_id } = order[0]; // if (teacher_id) { // const enrollmentResult = await EnrollmentServices.deleteEnrollment( // teacher_id, // course_id // ); // if (enrollmentResult instanceof ErrorResponseC) { // return enrollmentResult; // } // } } const sqlDeleteQuery = 'DELETE FROM orders WHERE order_id = ?'; await db.query(sqlDeleteQuery, [orderId]); const resp: ICode = orderLogs.DELETE_ORDER_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, null, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.DELETE_ORDER_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.DELETE_ORDER_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; /** * @description Get an order * @param orderId - Number * @returns ResponseT */ static getOrder = async (orderId: number): Promise => { try { const sqlquery = 'SELECT * FROM orders WHERE order_id = ?'; const [order] = await db.query(sqlquery, [orderId]); if (order.length === 0) { const msg = formatString(orderLogs.ORDER_ERROR_NOT_FOUND.message, { orderId, }); orderLogger.error(msg); return new ErrorResponseC( orderLogs.ORDER_ERROR_NOT_FOUND.type, HttpCodes.NotFound.code, msg ); } const resp: ICode = orderLogs.GET_ORDER_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, order[0], msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.ORDER_ERROR_GENERIC.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.ORDER_ERROR_GENERIC.type, HttpCodes.InternalServerError.code, msg ); } }; /** * @description Get all orders * @returns ResponseT */ static getOrders = async (): Promise => { try { // get orders where school_id is not null and join with schools table const sqlquery = 'SELECT o.*, u.email, s.schoolName, p.name as packName, c.title as courseName,p.nb_teachers_accounts FROM orders o LEFT JOIN schools s ON o.school_id = s.school_id LEFT JOIN users u ON s.user_id = u.user_id LEFT JOIN packs p ON p.pack_id = o.pack_id LEFT JOIN courses c ON c.course_id = o.course_id WHERE o.school_id IS NOT NULL ORDER BY o.createdAt DESC'; // 'SELECT o.*, s.schoolName FROM Orders o LEFT JOIN Schools s ON o.school_id = s.school_id WHERE o.school_id IS NOT NULL'; const [schoolOrders] = await db.query(sqlquery); // get orders where teacher_id is not null and get user_id from teachers table and join with users table const sqlquery2 = 'SELECT o.*, u.firstName, u.lastName, u.email, c.title as courseName FROM orders o LEFT JOIN teachers t ON o.teacher_id = t.teacher_id LEFT JOIN users u ON t.user_id = u.user_id JOIN courses c ON c.course_id = o.course_id WHERE o.teacher_id IS NOT NULL ORDER BY o.createdAt DESC'; const [teacherOrders] = await db.query(sqlquery2); const resp: ICode = orderLogs.GET_ORDERS_SUCCESS; const msg = resp.message; orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, { schoolOrders, teacherOrders }, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.GET_ORDERS_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.GET_ORDERS_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; /** * @description Get all orders by status * @param status - String * @returns ResponseT */ static getOrdersByStatus = async (status: string): Promise => { try { const sqlquery = 'SELECT * FROM orders WHERE status = ?'; const [orders] = await db.query(sqlquery, [status]); const resp: ICode = orderLogs.GET_ORDERS_BY_STATUS_SUCCESS; const msg = resp.message; orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, orders, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.GET_ORDERS_BY_STATUS_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.GET_ORDERS_BY_STATUS_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; /** * @description Update order status * @param orderId - Number * @param status - String * @returns ResponseT */ static updateOrderStatus = async ( orderId: number, status: string ): Promise => { try { const sqlUpdateQuery = 'UPDATE orders SET status = ? WHERE order_id = ?'; await db.query(sqlUpdateQuery, [status, orderId]); const resp: ICode = orderLogs.UPDATE_ORDER_STATUS_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, null, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.UPDATE_ORDER_STATUS_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.UPDATE_ORDER_STATUS_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; static getOrdersByInstructor = async ( inst_designer_id: number ): Promise => { try { const sqlquery = 'SELECT * FROM orders WHERE inst_designer_id = ?'; const [orders] = await db.query(sqlquery, [ inst_designer_id, ]); const resp: ICode = orderLogs.GET_ORDERS_BY_STATUS_SUCCESS; const msg = resp.message; orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, orders, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.GET_ORDERS_BY_STATUS_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.GET_ORDERS_BY_STATUS_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; static updateSchoolOrder = async ( orderId: number, course_id: number, pack_id: number, school_id: number, price: number, status: string, note: string | null ): Promise => { try { const updatedAt = new Date(); const sqlUpdateQuery = 'UPDATE orders SET course_id = ?, pack_id = ?, school_id = ?, price = ?, status = ?, note = ?, updatedAt = ? WHERE order_id = ?'; await db.query(sqlUpdateQuery, [ course_id, pack_id, school_id, price, status, note, updatedAt, orderId, ]); const resp: ICode = orderLogs.UPDATE_ORDER_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, null, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.UPDATE_ORDER_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.UPDATE_ORDER_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; static updateTeacherOrder = async ( orderId: number, course_id: number, pack_id: number, teacher_id: number, price: number, status: string, note: string | null ): Promise => { try { const updatedAt = new Date(); const sqlUpdateQuery = 'UPDATE orders SET course_id = ?, pack_id = ?, teacher_id = ?, price = ?, status = ?, note = ?, updatedAt = ? WHERE order_id = ?'; await db.query(sqlUpdateQuery, [ course_id, pack_id, teacher_id, price, status, note, updatedAt, orderId, ]); const resp: ICode = orderLogs.UPDATE_ORDER_SUCCESS; const msg = formatString(resp.message, { orderId, }); orderLogger.info(msg, { type: resp.type }); return new SuccessResponseC( resp.type, null, msg, HttpCodes.Accepted.code ); } catch (err) { const msg = formatString(orderLogs.UPDATE_ORDER_ERROR.message, { error: (err as Error)?.message || '', }); orderLogger.error(msg, err as Error); return new ErrorResponseC( orderLogs.UPDATE_ORDER_ERROR.type, HttpCodes.InternalServerError.code, msg ); } }; } // Orders Table: // order_id (Primary Key), // course_id (Foreign Key referencing Courses table), // pack_id (Foreign Key referencing Packs table), // school_id (Foreign Key referencing Schools table), // teacher_id (Foreign Key referencing Teachers table), // price // status // note