Untitled
unknown
plain_text
a year ago
19 kB
11
Indexable
const mongoose = require('mongoose');
const User = require('../Models/userModel.js');
const SubCategory = require('../Models/subcategoryModel.js');
const Group = require('../Models/groupModel.js');
const Brand = require('../Models/brandModel.js');
const Category = require('../Models/categoryModel.js');
const Product = require('../Models/productModel.js');
const AppError = require('../utils/appError.js');
const catchAsync = require('../utils/catchAsync.js');
const { isDecimal } = require('validator');
const Client = require('../Models/clientModel.js');
const Cart = require('../Models/cartModel.js');
const Order = require('../Models/orderModel.js');
const Retailer = require('../Models/retailerModel.js');
const Notification = require('../Models/notificationModel.js');
const Offer = require('../Models/offerModel.js');
const Socket = require('../socket/socketIndex.js');
const valid = require('../utils/validationfunctions.js');
const XLSX = require('xlsx');
///////////////
exports.AddOrder = catchAsync(async (req, res, next) => {
const { productDetails, billingDetails, userId } = req.body;
const session = await mongoose.startSession();
try {
session.startTransaction();
let total = 0;
const user = await checkUser(userId, next);
// await checkProductDetails(productDetails,session,next);
if (!Array.isArray(productDetails)) {
return next(new AppError('products Details not array', 400));
}
if (productDetails.length < 1) {
return next(new AppError('no products in this order', 400));
}
for (const prod of productDetails) {
const product = await Product.findById(toObjectId(prod.product, next));
if (!product) {
return next(new AppError('Product not found', 400));
}
if (prod.quantity < 1) {
return next(new AppError('invalid Quantity value', 400));
}
if (product.quantity < prod.quantity) {
return next(new AppError('Quantity for this Product not found', 400));
}
product.quantity = product.quantity - prod.quantity;
prod.initialPrice = product.pricing.initialPrice;
if (user.role == 'client') {
prod.price = product.pricing.publicPrice;
} else if (user.role == 'retailer') {
const retailer = await Retailer.findById({ _id: user.profile }).select('pricingType');
prod.price = product.pricing.discountPrices[retailer.pricingType - 1];
} else {
return next(new AppError("this user isn't client or retailer", 400));
}
if (product.offer) {
const offer = await Offer.findById(product.offer);
if (offer.status == true) {
prod.price = Number.parseFloat(prod.price * (1 - offer.discount / 100)).toFixed(2);
}
}
total += prod.price * prod.quantity;
await product.save({ session: session });
}
await checkbillingDetails(billingDetails, next);
const order = await Order.create(
[
{
products: productDetails,
cart_address: billingDetails,
totalPrice: Number.parseFloat(total).toFixed(2),
ordered_by: user._id
}
],
{ session }
);
if (user.role == 'client') {
await Client.updateOne({ _id: user.profile }, { $push: { orders: order[0]._id } }, { session });
} else if (user.role == 'retailer') {
await Retailer.updateOne({ _id: user.profile }, { $push: { orders: order[0]._id } }, { session });
}
const users = await User.find({ $or: [{ role: 'manager' }, { role: 'admin' }, { role: 'subadmin' }] });
const usersIds = [];
for (let i = 0; i < users.length; i++) {
const notification = await Notification.create([{ content: 'new order', type: 'order' }], { session });
await User.updateOne({ _id: users[i]._id }, { $push: { notifications: notification[0]._id } }, { session });
usersIds.push({ id: users[i]._id.toString(), data: notification });
}
Socket.SocketConnectedList(usersIds);
await session.commitTransaction();
session.endSession();
res.status(200).json({ message: 'Order added successfully', order: order });
} catch (error) {
await session.abortTransaction();
session.endSession();
return next(error);
}
});
///////////////
const checkUser = async (userId, next) => {
const user = await User.findById(toObjectId(userId, next));
if (!user) {
return next(new AppError('User not found', 400));
}
switch (user.role) {
case 'client':
const client = await Client.findById(user.profile);
if (!client) {
return next(new AppError('Client profile not found', 400));
}
break;
case 'retailer':
const retailer = await Retailer.findById(user.profile);
if (!retailer) {
return next(new AppError('Retailer profile not found', 400));
}
break;
default:
return next(new AppError('this role does not have access for this function', 401));
}
return user;
};
const checkbillingDetails = async (billingDetails, next) => {
if (!valid.isValidPhoneNumber(billingDetails.phone)) {
return next(new AppError('Phone is required', 400));
}
if (!billingDetails.city) {
return next(new AppError('city is required', 400));
}
if (!billingDetails.zipCode) {
return next(new AppError('zip_code is required', 400));
}
if (!billingDetails.address) {
return next(new AppError('adresse is required', 400));
}
if (!billingDetails.first_name) {
return next(new AppError('first name is required', 400));
}
if (!billingDetails.last_name) {
return next(new AppError('last name is required', 400));
}
};
exports.getOrders = catchAsync(async (req, res, next) => {
const { id } = req.params;
let orders = null;
const user = await checkUser(id, next);
if (user.role == 'client') {
const pathsAndFields = { path: 'orders', populate: { path: 'products.product', select: ['name'] } };
orders = await Client.find({ _id: user.profile }).populate(pathsAndFields);
}
if (user.role == 'retailer') {
const pathsAndFields = {
path: 'orders',
select: ['products'],
populate: { path: 'products.product', select: ['name'] }
};
orders = await Retailer.find({ _id: user.profile }).populate(pathsAndFields);
}
const data = orders[0].orders.reduce((result, order) => {
let obj = {};
obj.item_count = order.products.length;
obj.id = order._id;
obj.totalPrice = order.totalPrice;
obj.status = order.status;
obj.createdAt = order.createdAt;
result.push(obj);
return result;
}, []);
res.status(200).json({ message: 'success', orders: data });
});
exports.getOrderDetails = catchAsync(async (req, res, next) => {
const { id } = req.params;
const pathsAndFields = { path: 'products.product', select: ['name', 'images'] };
const order = await Order.findById(toObjectId(id, next)).populate(pathsAndFields);
res.status(200).json({ message: 'success', order: order });
});
exports.changeOrderStatus = catchAsync(async (req, res, next) => {
const { id, status } = req.body;
const order_id = toObjectId(id, next);
const session = await mongoose.startSession();
try {
session.startTransaction();
const order = await Order.updateOne({ _id: order_id }, { status: status }, { runValidators: true }, { session });
if (order.matchedCount > 0) {
const users = await Order.aggregate([
{ $match: { _id: order_id } },
{
$lookup: {
from: 'users',
localField: 'ordered_by',
foreignField: '_id',
pipeline: [{ $project: { name: 1 } }],
as: 'user'
}
}
]);
const usersIds = [];
for (let i = 0; i < users[0].user.length; i++) {
const notification = await Notification.create(
[{ content: 'Your order status has been changed, new status :' + status + '', type: 'order' }],
{ session }
);
await User.updateOne({ _id: users[0].user[i]._id }, { $push: { notifications: notification[0]._id } });
usersIds.push({ id: users[0].user[i]._id.toString(), data: notification });
}
Socket.SocketConnectedList(usersIds);
await session.commitTransaction();
session.endSession();
res.status(200).json({ status: 'success', order: order });
} else {
res.status(400).json({ status: 'error', message: 'order id invalid' });
}
} catch (error) {
await session.abortTransaction();
session.endSession();
return next(error);
}
});
exports.AddTrackingAndColis = catchAsync(async (req, res, next) => {
const { tracking_number, colis_number, orderId } = req.query;
console.log('****, ', orderId);
const order = await Order.findById(toObjectId(orderId, next));
if (!order) {
return next(new AppError('Order not found', 400));
}
if (tracking_number) {
order.nb_tracking = tracking_number;
}
if (colis_number) {
order.nb_colis = colis_number;
}
await order.save();
res.status(200).json({ message: 'success', data: order });
});
exports.filterOrders = catchAsync(async (req, res, next) => {
const { category, status, startDate, endDate, limitDate } = req.body;
const page = parseInt(req.query.page);
const limit = parseInt(req.query.limit);
if (!page || !limit) {
return next(new AppError('page and limit required', 400));
}
let category_filter = {};
let filter = {};
if (category) {
const Id = toObjectId(category, next);
let id_category = await Category.findById(Id);
if (id_category) {
//arrayAND.push({ categories: Id });
category_filter.categories = Id;
} else {
return next(new AppError('invalid categorie value', 400));
}
}
if (status == 'pending' || status == 'processing' || status == 'cancel' || status == 'delivered') {
filter.status = status;
}
if (limitDate) {
var currentDate = new Date();
let days = parseInt(limitDate);
currentDate.setDate(currentDate.getDate() - days);
filter.createdAt = { $gte: currentDate };
}
if (startDate && !endDate) {
let date = new Date(startDate);
if (date == 'Invalid Date') {
return next(new AppError('Invalid Date', 400));
}
filter.createdAt = { $gte: date };
}
if (!startDate && endDate) {
let date = new Date(endDate);
date.setDate(date.getDate() + 1);
if (date == 'Invalid Date') {
return next(new AppError('Invalid Date', 400));
}
filter.createdAt = { $lte: date };
}
if (startDate && endDate) {
let start_date = new Date(startDate);
let end_date = new Date(endDate);
end_date.setDate(end_date.getDate() + 1);
if (start_date == 'Invalid Date' || end_date == 'Invalid Date') {
return next(new AppError('Invalid Date', 400));
}
filter.createdAt = { $gte: start_date, $lte: end_date };
}
const results = await Order.aggregate([
{ $match: filter },
{ $sort: { createdAt: -1 } },
{
$lookup: {
from: 'products',
localField: 'products.product',
foreignField: '_id',
pipeline: [{ $match: category_filter }],
as: 'product'
}
},
{
$lookup: {
from: 'users',
localField: 'ordered_by',
foreignField: '_id',
pipeline: [{ $project: { name: 1 } }],
as: 'clientName'
}
},
{ $limit: (page - 1) * limit + limit },
{ $skip: (page - 1) * limit }
]);
const data = results.reduce((result, order) => {
if (order.product.length > 0) {
let obj = {};
obj.units = order.products.length;
obj.id = order._id;
obj.product = {};
obj.product.name = order.product[0]?.name;
obj.product.image = order.product[0]?.images[0];
obj.price = order.totalPrice;
obj.status = order.status;
obj.nb_tracking = order?.nb_tracking || '';
obj.nb_colis = order?.nb_colis || '';
obj.clientName = order.clientName[0]?.name;
result.push(obj);
}
return result;
}, []);
const count = await Order.find(filter).count();
res.status(200).json({ status: 'success', count, data });
});
exports.OrdersToExcel = catchAsync(async (req, res, next) => {
const { category, status, startDate, endDate, limitDate } = req.query;
let category_filter = {};
let filter = {};
if (category) {
const Id = toObjectId(category, next);
let id_category = await Category.findById(Id);
if (id_category) {
//arrayAND.push({ categories: Id });
category_filter.categories = Id;
} else {
return next(new AppError('invalid categorie value', 400));
}
}
if (status == 'pending' || status == 'processing' || status == 'cancel' || status == 'delivered') {
filter.status = status;
}
if (limitDate) {
var currentDate = new Date();
let days = parseInt(limitDate);
currentDate.setDate(currentDate.getDate() - days);
filter.createdAt = { $gte: currentDate };
}
if (startDate && !endDate) {
let date = new Date(startDate);
if (date == 'Invalid Date') {
return next(new AppError('Invalid Date', 400));
}
filter.createdAt = { $gte: date };
}
if (!startDate && endDate) {
let date = new Date(endDate);
date.setDate(date.getDate() + 1);
if (date == 'Invalid Date') {
return next(new AppError('Invalid Date', 400));
}
filter.createdAt = { $lte: date };
}
if (startDate && endDate) {
let start_date = new Date(startDate);
let end_date = new Date(endDate);
end_date.setDate(end_date.getDate() + 1);
if (start_date == 'Invalid Date' || end_date == 'Invalid Date') {
return next(new AppError('Invalid Date', 400));
}
filter.createdAt = { $gte: start_date, $lte: end_date };
console.log('date :', end_date);
}
const results = await Order.aggregate([
{ $match: filter },
{ $sort: { createdAt: -1 } },
{
$lookup: {
from: 'products',
localField: 'products.product',
foreignField: '_id',
pipeline: [{ $match: category_filter }],
as: 'product'
}
},
{
$lookup: {
from: 'users',
localField: 'ordered_by',
foreignField: '_id',
pipeline: [{ $project: { name: 1 } }],
as: 'clientName'
}
}
]);
const flatData = results
.map((order) => {
return {
'Order ID': order._id.toString(),
'First Name': order?.cart_address?.first_name,
'Last Name': order?.cart_address?.last_name,
Phone: order?.cart_address?.phone,
City: order?.cart_address?.city,
'Zip Code': order?.cart_address?.zipCode,
Address: order?.cart_address?.address,
Units: order?.products.length,
'Total Price': order?.totalPrice,
Status: order.status,
'Created At': formatDateToYYYYMMDD(order?.createdAt),
'Updated At': formatDateToYYYYMMDD(order?.updatedAt),
'Tracking Number': order?.nb_tracking,
'Number of Parcels': order?.nb_colis
};
})
.flat();
const worksheet = XLSX.utils.json_to_sheet(flatData);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Orders');
// Generate Excel file buffer
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' });
res.setHeader('Content-Disposition', 'attachment; filename="OrdersData.xlsx"');
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
// Send the buffer as a response
return res.send(excelBuffer);
});
function formatDateToYYYYMMDD(date) {
if (date) {
if (!(date instanceof Date)) {
throw new Error('Invalid date object');
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-based, so add 1
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
}
exports.getListOrders = catchAsync(async (req, res, next) => {
const results = await Order.aggregate([
{
$lookup: {
from: 'products',
localField: 'products.0.product',
foreignField: '_id',
pipeline: [{ $project: { name: 1, images: 1 } }],
as: 'product'
}
},
{
$lookup: {
from: 'users',
localField: 'ordered_by',
foreignField: '_id',
pipeline: [{ $project: { name: 1 } }],
as: 'clientName'
}
}
]);
const data = results.reduce((result, order) => {
let obj = {};
obj.units = order.products.length;
obj.id = order._id;
obj.product = {};
obj.product.name = order.product[0]?.name;
obj.product.image = order.product[0]?.images[0];
obj.price = order.totalPrice;
obj.status = order.status;
obj.clientName = order.clientName[0]?.name;
result.push(obj);
return result;
}, []);
res.status(200).json({ status: 'success', data: data });
});
exports.getListOrdersByUser = catchAsync(async (req, res, next) => {
const { id } = req.params;
let orders = null;
const user = await checkUser(id, next);
if (user.role == 'client') {
const pathsAndFields = { path: 'orders', populate: { path: 'products.0.product', select: ['name', 'images'] } };
orders = await Client.find({ _id: user.profile }).populate(pathsAndFields);
}
if (user.role == 'retailer') {
const pathsAndFields = { path: 'orders', populate: { path: 'products.0.product', select: ['name', 'images'] } };
orders = await Retailer.find({ _id: user.profile }).populate(pathsAndFields);
}
const data = orders[0].orders.reduce((result, order) => {
let obj = {};
obj.item_count = order.products.length;
obj.id = order._id;
obj.totalPrice = order.totalPrice;
obj.status = order.status;
obj.createdAt = order.createdAt;
obj.name = order.products[0].product?.name;
obj.image = order.products[0]?.product?.images[0];
result.push(obj);
return result;
}, []);
res.status(200).json({ message: 'success', orders: data });
});
exports.getOrderInvoce = catchAsync(async (req, res, next) => {
const { id } = req.params;
const pathsAndFields = [
{ path: 'products.product', select: ['name', 'images'] },
{ path: 'ordered_by', select: ['name', 'phone,email'] }
];
const order = await Order.findById(toObjectId(id, next)).populate(pathsAndFields);
res.status(200).json({ message: 'success', order: order });
});
const toObjectId = (id, next) => {
try {
return new mongoose.Types.ObjectId(id);
} catch (e) {
return next(new AppError('Invalid id.', 401));
}
};
Editor is loading...
Leave a Comment