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<ResponseT> => {
try {
// check if the status is active
const courseStatusQuery =
'SELECT status FROM courses WHERE course_id = ?';
const [courseStatus] = await db.query<RowDataPacket[]>(
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<OrderResI[]>(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<ResultSetHeader[]>(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<IOrderLogs> = 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<ResponseT> => {
try {
// check if the status is active
const courseStatusQuery =
'SELECT status FROM courses WHERE course_id = ?';
const [courseStatus] = await db.query<RowDataPacket[]>(
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<RowDataPacket[]>(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<ResultSetHeader[]>(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<RowDataPacket[]>(sqlDeleteQuery, [orderId]);
return enrollmentResult;
}
const order: OrderI = {
order_id: orderId,
course_id,
pack_id,
teacher_id,
price,
status,
note,
};
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
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<OrderResI[]>(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<RowDataPacket[]>(sqlDeleteQuery, [orderId]);
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM orders WHERE order_id = ?';
const [order] = await db.query<OrderResI[]>(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<IOrderLogs> = 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<ResponseT> => {
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<OrderResI[]>(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<OrderResI[]>(sqlquery2);
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM orders WHERE status = ?';
const [orders] = await db.query<OrderResI[]>(sqlquery, [status]);
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
try {
const sqlUpdateQuery = 'UPDATE orders SET status = ? WHERE order_id = ?';
await db.query<OrderResI[]>(sqlUpdateQuery, [status, orderId]);
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
try {
const sqlquery = 'SELECT * FROM orders WHERE inst_designer_id = ?';
const [orders] = await db.query<OrderResI[]>(sqlquery, [
inst_designer_id,
]);
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
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<RowDataPacket[]>(sqlUpdateQuery, [
course_id,
pack_id,
school_id,
price,
status,
note,
updatedAt,
orderId,
]);
const resp: ICode<IOrderLogs> = 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<ResponseT> => {
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<RowDataPacket[]>(sqlUpdateQuery, [
course_id,
pack_id,
teacher_id,
price,
status,
note,
updatedAt,
orderId,
]);
const resp: ICode<IOrderLogs> = 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