feat: complete day 2

This commit is contained in:
Ayobami
2025-07-11 18:05:50 +01:00
parent b277c8182d
commit 325788cb39
8 changed files with 456 additions and 5 deletions
+82
View File
@@ -0,0 +1,82 @@
const { Op } = require("sequelize");
class PaginationService {
/**
* Handle offset-based pagination with sorting
*/
static async paginateWithSort(model, options = {}) {
const {
page = 1,
limit = 10,
sort = "id",
direction = "ASC",
where = {},
} = options;
const offset = (page - 1) * limit;
const order = [[sort, direction.toUpperCase()]];
const { count, rows } = await model.findAndCountAll({
where,
order,
limit: parseInt(limit),
offset: parseInt(offset),
});
const totalPages = Math.ceil(count / limit);
return {
total: count,
page: parseInt(page),
totalPages,
list: rows,
};
}
/**
* Handle cursor-based pagination
*/
static async paginateWithCursor(model, options = {}) {
const {
id,
limit = 10,
sort = "id",
direction = "ASC",
where = {},
} = options;
const order = [[sort, direction.toUpperCase()]];
const cursorWhere = {
...where,
[sort]: {
[direction.toUpperCase() === "ASC" ? Op.gt : Op.lt]: id,
},
};
const rows = await model.findAll({
where: cursorWhere,
order,
limit: parseInt(limit),
});
return {
id: parseInt(id),
list: rows,
};
}
/**
* Get odd order IDs
*/
static async getOddOrders(model) {
return await model.findAll({
where: {
id: {
[Op.mod]: [2, 1], // id % 2 = 1 (odd numbers)
},
},
});
}
}
module.exports = PaginationService;
+169
View File
@@ -0,0 +1,169 @@
const { Op, fn, col, literal } = require("sequelize");
class ReportService {
/**
* Get total sales for a specific month and year
*/
static async getMonthlySales(model, month, year) {
const result = await model.findOne({
attributes: [[fn("SUM", col("amount")), "total_amount"]],
where: {
created_at: {
[Op.and]: [
literal(`MONTH(created_at) = ${month}`),
literal(`YEAR(created_at) = ${year}`),
],
},
},
});
return {
month: parseInt(month),
year: parseInt(year),
total_amount: parseFloat(result?.dataValues?.total_amount || 0),
};
}
/**
* Get total sales for a date range
*/
static async getSalesByDateRange(model, fromDate, toDate) {
// Ensure dates are in correct order
const startDate = new Date(fromDate) < new Date(toDate) ? fromDate : toDate;
const endDate = new Date(fromDate) < new Date(toDate) ? toDate : fromDate;
const result = await model.findOne({
attributes: [[fn("SUM", col("amount")), "total_amount"]],
where: {
created_at: {
[Op.between]: [startDate, endDate],
},
},
});
return {
from_date: startDate,
to_date: endDate,
total_amount: parseFloat(result?.dataValues?.total_amount || 0),
};
}
/**
* Get monthly sales for a year (only months with sales > 0)
*/
static async getMonthlySalesByYear(model, year) {
const results = await model.findAll({
attributes: [
[fn("MONTH", col("created_at")), "month"],
[fn("SUM", col("amount")), "total_amount"],
],
where: {
created_at: {
[Op.and]: [literal(`YEAR(created_at) = ${year}`)],
},
},
group: [fn("MONTH", col("created_at"))],
having: literal("SUM(amount) > 0"),
order: [[fn("MONTH", col("created_at")), "ASC"]],
});
return results.map((result) => ({
month: parseInt(result.dataValues.month),
total_amount: parseFloat(result.dataValues.total_amount),
}));
}
/**
* Get monthly sales for a year by user_id (only months with sales > 0)
*/
static async getMonthlySalesByUser(model, year, userId) {
const results = await model.findAll({
attributes: [
[fn("MONTH", col("created_at")), "month"],
[fn("SUM", col("amount")), "total_amount"],
],
where: {
created_at: {
[Op.and]: [literal(`YEAR(created_at) = ${year}`)],
},
user_id: userId,
},
group: [fn("MONTH", col("created_at"))],
having: literal("SUM(amount) > 0"),
order: [[fn("MONTH", col("created_at")), "ASC"]],
});
return results.map((result) => ({
month: parseInt(result.dataValues.month),
total_amount: parseFloat(result.dataValues.total_amount),
}));
}
/**
* Get monthly sales for a year by shipping_dock_id (only months with sales > 0)
*/
static async getMonthlySalesByShippingDock(model, year, shippingDockId) {
const results = await model.findAll({
attributes: [
[fn("MONTH", col("created_at")), "month"],
[fn("SUM", col("amount")), "total_amount"],
],
where: {
created_at: {
[Op.and]: [literal(`YEAR(created_at) = ${year}`)],
},
shipping_dock_id: shippingDockId,
},
group: [fn("MONTH", col("created_at"))],
having: literal("SUM(amount) > 0"),
order: [[fn("MONTH", col("created_at")), "ASC"]],
});
return results.map((result) => ({
month: parseInt(result.dataValues.month),
total_amount: parseFloat(result.dataValues.total_amount),
}));
}
/**
* Get order count per month for a user in a year (include months with 0 orders)
*/
static async getOrderCountByUser(model, year, userId) {
// First get all months with orders
const orderMonths = await model.findAll({
attributes: [
[fn("MONTH", col("created_at")), "month"],
[fn("COUNT", col("id")), "order_count"],
],
where: {
created_at: {
[Op.and]: [literal(`YEAR(created_at) = ${year}`)],
},
user_id: userId,
},
group: [fn("MONTH", col("created_at"))],
order: [[fn("MONTH", col("created_at")), "ASC"]],
});
// Create a map of months with orders
const monthMap = {};
orderMonths.forEach((result) => {
monthMap[parseInt(result.dataValues.month)] = parseInt(
result.dataValues.order_count
);
});
// Create result array with all 12 months
const result = [];
for (let month = 1; month <= 12; month++) {
result.push({
month,
order_count: monthMap[month] || 0,
});
}
return result;
}
}
module.exports = ReportService;