Sindbad~EG File Manager
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const db = require("../models");
const { Op } = require("sequelize");
const { col } = require("sequelize");
const {
formatTimeRange,
calculateDateRange,
} = require("../constants/formatTimeRange");
const crypto = require("crypto");
const nodemailer = require("nodemailer");
const auctioneerLogin = async (req, res) => {
try {
let { business_email, password } = req.body;
// Convert email to lowercase
business_email = business_email.toLowerCase();
let result = await db.tblAuctioneer.findOne({
where: {
business_email: business_email,
},
});
if (!result) {
return res
.status(404)
.json({ status: 404, message: "Invalid credentials" });
}
const isMatched = await bcrypt.compare(password, result.password);
if (!isMatched) {
return res
.status(403)
.json({ status: 403, message: "Invalid credentials" });
}
let token = await jwt.sign(
{
business_email: result.business_email,
auctioneer_id: result.auctioneer_id,
},
process.env.JWT_KEY
);
const {
resetPasswordToken,
password: newPassword,
resetPasswordExpires,
...formattedData
} = result.dataValues;
return res.json({
status: 200,
message: "Success",
data: [
{
token,
...formattedData,
},
],
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const validPassword = (password, storedHash) => {
return bcrypt.compareSync(password, storedHash);
};
function getTranperter() {
const transporter = nodemailer.createTransport({
host: process.env.MAIL_SERVER_HOST, // Replace with your mail server host from cPanel
port: 465, // Secure SMTP port number provided by your hosting (commonly 465 or 587)
secure: true, // True for 465, false for other ports
auth: {
user: process.env.EMAIL_USERNAME, // The email account you created in cPanel
pass: process.env.EMAIL_PASSWORD, // Email account password
},
});
return transporter;
}
// Helper functions for password hashing
const generateHash = (password) => {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
const forgotPassword = async (req, res) => {
let { business_email } = req.body;
business_email = business_email?.toLowerCase();
let transporter;
if (!transporter) {
try {
transporter = getTranperter();
} catch (error) {
return res.status(500).json({
status: 500,
message: "Failed to send email due to internal error",
});
}
}
// Generate token
const token = crypto.randomBytes(20).toString("hex");
try {
const user = await db.tblAuctioneer.findOne({
where: { business_email: business_email },
});
if (!user) {
return res.status(400).json({
status: 400,
error: "No account with that email address exists.",
});
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
await user.save();
const mailOptions = {
to: user.business_email,
from: process.env.EMAIL_USERNAME,
subject: "Password Reset Confirmation",
text: `Hello,
Please click on the following link, or paste it into your browser to complete the password reset process:
${process.env.CLIENT_URL}/reset/${token}
If you did not request a password reset, please ignore this email.
Best regards,
infinitibizsol`,
html: `
<html>
<body>
<p>Hello,</p>
<p>Please click on the following link, or paste it into your browser to complete the password reset process:</p>
<a href="${process.env.CLIENT_URL}/reset/${token}" target="_blank">Reset Password</a>
<p>If you did not request a password reset, please ignore this email.</p>
<p>Best regards,<br>
infinitibizsol</p>
</body>
</html>`,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return res.status(500).send(error);
}
transporter.close();
});
res.json({
status: 200,
message: "success",
data: {
notification: `An e-mail has been sent to ${user.business_email} with further instructions.`,
token: token,
},
});
} catch (error) {
return res.status(500).send(error.message);
}
};
const resetPasswordViaToken = async (req, res) => {
const { token } = req.params;
const { newPassword } = req.body;
try {
const user = await db.tblAuctioneer.findOne({
where: {
resetPasswordToken: token,
resetPasswordExpires: { [Op.gt]: Date.now() },
},
});
if (!user) {
return res.status(400).json({
status: 400,
error: "Password reset token is invalid or has expired.",
});
}
user.password = generateHash(newPassword);
user.resetPasswordToken = null;
user.resetPasswordExpires = null;
await user.save();
res.status(200).json({
status: 200,
message: "Success! Your password has been changed.",
});
} catch (error) {
res.status(500).send(error.message);
}
};
const getAuctioneerProfile = async (req, res) => {
const auctioneer_id = req.params.id;
try {
let result = await db.tblAuctioneer.findOne({
where: {
auctioneer_id: auctioneer_id,
},
});
if (!result) {
return res.json({ status: 404, message: "No user Found" });
}
const {
resetPasswordToken,
password,
resetPasswordExpires,
...formattedData
} = result.dataValues;
return res.json({
status: 200,
message: "Success",
data: [
{
...formattedData,
},
],
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const removeAuctioneer = async (req, res) => {
const { business_email } = req.body;
let transaction;
try {
transaction = await db.sequelize.transaction(); // Start a new transaction
const auctioneer = await db.tblAuctioneer.findOne({
where: { business_email },
transaction,
});
if (!auctioneer) {
await transaction.rollback(); // Ensure transaction is rolled back if auctioneer does not exist
return res
.status(404)
.json({ status: 404, message: "Auctioneer not found." });
}
const opportunities = await db.tblOpportunity.findAll({
where: { auctioneer_id: auctioneer.auctioneer_id },
transaction,
});
const opportunity_ids = opportunities.map(
(opportunity) => opportunity.opportunity_id
);
vehicle_run = await db.tblVehicleRun.findAll({
where: {
opportunity_id: {
[Op.in]: opportunity_ids, // Use the `Op.in` operator to look for any opportunity_id in the provided array
},
},
transaction,
});
const vehicle_run_ids = vehicle_run.map((item) => item.vehicle_run_id);
const vehicle_run_fee_deleted_count = await db.tblVehicleRunFee.destroy({
where: { vehicle_run_id: vehicle_run_ids },
transaction,
});
const auctioneer_feeses_deleted_count = await db.tblAuctioneerFee.destroy({
where: { auctioneer_id: auctioneer.auctioneer_id },
transaction,
});
const vehicle_run_deleted_count = await db.tblVehicleRun.destroy({
where: { opportunity_id: opportunity_ids },
transaction,
});
const opportunity_deleted_count = await db.tblOpportunity.destroy({
where: { opportunity_id: opportunity_ids },
transaction,
});
const subscription_deleted_count = await db.tblUserSubAuctioneer.destroy({
where: { auctioneer_id: auctioneer.auctioneer_id },
transaction,
});
const auctioneer_deleted_count = await db.tblAuctioneer.destroy({
where: { auctioneer_id: auctioneer.auctioneer_id },
transaction,
});
await transaction.commit(); // Commit all changes
return res.status(200).json({
message: "Auctioneer and related data successfully deleted.",
details: {
vehicle_runs: vehicle_run_deleted_count,
vehicle_runs_fee: vehicle_run_fee_deleted_count,
opportunities: opportunity_deleted_count,
subscriptions: subscription_deleted_count,
auctioneer_fee: auctioneer_feeses_deleted_count,
auctioneer: auctioneer_deleted_count,
},
});
} catch (error) {
if (transaction) {
try {
// Additional safeguard to ensure that we do not call rollback on an already finished transaction.
if (!transaction.finished) {
await transaction.rollback();
}
} catch (rollbackError) {
console.error("Rollback error:", rollbackError);
}
}
return res.status(500).json({
message: "Internal Server Error",
error: error.message,
});
}
};
const updateAuctioneerPassword = async (req, res) => {
try {
let { auctioneer_id, newPassword } = req.body;
if (newPassword) {
const salt = await bcrypt.genSalt(10);
// const hashedPassword = await bcrypt.hash(newPassword, salt);
const hashedPassword = generateHash(newPassword);
let result = await db.tblAuctioneer.update(
{ password: hashedPassword },
{ where: { auctioneer_id: auctioneer_id } }
);
return res
.status(200)
.json({ status: 200, message: "password updated successfully." });
} else {
return res.json({ status: 400, message: "Please enter new password." });
}
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
//Hamza Ali
const GetAuctioneerUsers = async (req, res) => {
try {
// let auctioneerId = req.user.auctioneer_id;
let {
timeRange = "currentweek",
auctioneerId,
weekId,
sortBy,
orderDirection,
} = req.body;
timeRange = formatTimeRange(timeRange);
const currentDate = new Date();
const weekRange = calculateDateRange(timeRange);
const result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: {
week_id: weekId,
auctioneer_id: auctioneerId,
},
include: [
{
model: db.tblUser,
attributes: ["user_id", "firstname", "lastname", "business_name"],
},
{
model: db.tblVehicleRun,
include: [
{
model: db.tblVehicle,
},
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
},
],
},
],
},
],
});
// return res.json(result);
const formattedData = result.map((item) => ({
user_id: item.tblUser.user_id,
firstname: item.tblUser.firstname,
lastname: item.tblUser.lastname,
business_name: item.tblUser.business_name,
tblVehicles: item.tblVehicleRuns.map((vehicleRun) => {
const vehicle = vehicleRun.tblVehicle || {};
const auctionLane = vehicleRun.tblAuctionLane || {
lane_id: null,
name: null,
tblAuction: {
auction_id: null,
name: null,
},
};
const auction = auctionLane.tblAuction;
return {
vehicle_id: vehicle.vehicle_id,
vin: vehicle.vin,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
trim: vehicle.trim,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name || null,
details: vehicle.details || null,
condition_light: vehicleRun.condition_light,
announcements: vehicleRun.announcements,
reserve: vehicleRun.reserve,
sale_price: vehicleRun.sale_price,
vehicle_total_fee: vehicleRun.vehicle_total_fee || null,
net_proceeds: vehicleRun.net_proceeds || null,
sale_status: vehicleRun.sale_status,
run_no: vehicleRun.run_no,
lane_id: auctionLane.lane_id,
lane_name: auctionLane.name,
auction_name: auction.name,
};
}),
}));
return res.json({
status: 200,
message: "Success",
filter_type: "whole_saler",
data: formattedData,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const GetAuctioneerUsersOnly = async (req, res) => {
try {
const { auctioneerId, weekId, orderDirection, sortBy } = req.body;
const { sequelize, tblUser, tblOpportunity, tblVehicle } = db;
const result = await tblUser.findAll({
attributes: [
"user_id",
"firstname",
"lastname",
[
sequelize.fn(
"COUNT",
sequelize.col("tblOpportunities.tblVehicleRuns.opportunity_id")
),
"units",
],
],
include: [
{
model: tblOpportunity,
attributes: [],
include: [
{
model: db.tblVehicleRun,
attributes: [],
raw: true,
},
],
where: {
auctioneer_id: auctioneerId,
week_id: parseInt(weekId),
},
},
],
group: ["tblUser.user_id", "tblOpportunities.opportunity_id"],
});
return res.json({
status: 200,
message: "Success",
filter_type: "user",
data: result,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const updateVehicleStatus = async (req, res) => {
try {
let result;
const vehicle_id = req.body.vehicle_id;
[result] = await db.tblVehicleRun.findAll({
where: {
vehicle_id: vehicle_id,
},
});
if (!result) {
await db.tblVehicleRun.create(req.body);
} else {
await db.tblVehicleRun.update(req.body, {
where: {
vehicle_id: vehicle_id,
},
});
}
return res.json({ status: 200, message: "Success" });
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const updateAuctioneerProfile = async (req, res) => {
let { auctioneer_id, ...data } = req.body;
data.business_email = data.business_email.toLowerCase();
if (req.body.password) {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt);
data.password = hashedPassword;
}
try {
let result = await db.tblAuctioneer.update(data, {
where: {
auctioneer_id: req.body.auctioneer_id,
},
});
return res.json({
status: 200,
message: "profile updated successfully.",
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
//Auctioneer Side
const getAllAssignedVehicles = async (req, res) => {
try {
let {
timeRange = "currentweek",
auctioneer_id,
user_id,
weekId,
} = req.body;
timeRange = formatTimeRange(timeRange);
const currentDate = new Date();
const weekRange = calculateDateRange(timeRange);
const week_id = parseInt(weekId);
let result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: {
user_id: user_id,
week_id: week_id,
auctioneer_id: auctioneer_id,
},
include: [
{
model: db.tblVehicle,
raw: true,
where: {
user_id: user_id,
opportunity_id: col("tblOpportunity.opportunity_id"),
},
include: [
{
model: db.tblVehicleRun,
raw: true,
include: [
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
raw: true,
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
raw: true,
},
],
},
],
},
],
},
],
// order: [["createdAt", "ASC"]]
});
const formattedData = result.flatMap((user) =>
user.tblVehicles.flatMap((vehicle) => {
const run = vehicle.tblVehicleRuns[0];
return {
vehicle_id: vehicle.vehicle_id,
vin: vehicle.vin,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
trim: vehicle.trim,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name,
details: vehicle.details,
opportunity_id: vehicle.opportunity_id,
user_id: vehicle.user_id,
createdAt: vehicle.createdAt,
updatedAt: vehicle.updatedAt,
vehicle_run_id: run.vehicle_run_id,
condition_light: run.condition_light,
announcements: run.announcements || null,
reserve: run.reserve || null,
sale_price: run.sale_price || null,
auction_fee: run.auction_fee || null,
net_profit: run.net_profit || null,
sale_status: run.sale_status || false,
run_no: run.run_no || null,
lane_id: run.lane_id || null,
lane_name: run.tblAuctionLane
? run.tblAuctionLane.name || null
: null,
auction_id:
run.tblAuctionLane && run.tblAuctionLane.tblAuction
? run.tblAuctionLane.tblAuction.auction_id || null
: null,
auction_name:
run.tblAuctionLane && run.tblAuctionLane.tblAuction
? run.tblAuctionLane.tblAuction.name || null
: null,
};
})
);
return res.json({ status: 200, message: "Success", data: formattedData });
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const getAllAssignedVehiclesOnly = async (req, res) => {
try {
let {
timeRange = "currentweek",
auctioneer_id,
user_id,
weekId,
sortBy = "vehicle_id",
orderDirection = "ASC",
} = req.body;
const week_id = parseInt(weekId);
timeRange = formatTimeRange(timeRange);
let result;
result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: {
user_id: user_id,
week_id: week_id,
auctioneer_id: auctioneer_id,
},
include: [
{
model: db.tblVehicleRun,
raw: true,
where: {
opportunity_id: col("tblOpportunity.opportunity_id"),
},
include: [
{
model: db.tblVehicle,
raw: true,
},
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
raw: true,
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
raw: true,
},
],
},
],
},
],
order: [[db.tblVehicleRun, db.tblVehicle, sortBy, orderDirection]],
});
// return res.json(result);
const transformedData = result.flatMap((opportunity) =>
opportunity.tblVehicleRuns.map((run) => ({
vehicle_id: run.vehicle_id,
vin: run.tblVehicle.vin,
year: run.tblVehicle.year,
make: run.tblVehicle.make,
model: run.tblVehicle.model,
trim: run.tblVehicle.trim,
mileage: run.tblVehicle.mileage,
color: run.tblVehicle.color,
color_name: run.tblVehicle.color_name,
details: run.tblVehicle.details,
opportunity_id: run.opportunity_id,
user_id: run.tblVehicle.user_id,
vehicle_run_id: run.vehicle_run_id,
condition_light: run.condition_light || 4,
announcements: run.announcements,
reserve: run.reserve || 0,
sale_price: run.sale_price || 0,
vehicle_total_fee: run.vehicle_total_fee || 0,
net_proceeds: run.net_proceeds || null,
sale_status: run.sale_status || false,
run_no: run.run_no || null,
auction_fee: run.auction_fee || 300,
lane_id: run.lane_id || null,
// Additional fields from tblAuctionLane and nested tblAuction if present
lane_name: run.tblAuctionLane ? run.tblAuctionLane.name : null,
auction_id:
run.tblAuctionLane && run.tblAuctionLane.tblAuction
? run.tblAuctionLane.tblAuction.auction_id
: null,
auction_name:
run.tblAuctionLane && run.tblAuctionLane.tblAuction
? run.tblAuctionLane.tblAuction.name
: null,
}))
);
return res.json({ status: 200, message: "Success", data: transformedData });
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
//Hamza Ali
const sortAuctioneerVehicles = async (req, res) => {
try {
const { auctioneerId, weekId, orderDirection, sortBy } = req.body;
// Find user_ids from tblOpportunity based on auctioneerId and weekId
const userOpportunityIds = await db.tblOpportunity.findAll({
attributes: ["user_id"],
where: {
auctioneer_id: auctioneerId,
week_id: parseInt(weekId),
},
raw: true,
});
// Extract user_ids from the result
const userIds = userOpportunityIds.map(
(opportunity) => opportunity.user_id
);
// Find user data from tblUser and tblVehicle based on the obtained user_ids
let whereClause = {};
// Adjust the where clause based on sortBy
if (sortBy == "sold_price") {
sortBy = "vehicle_id";
}
const result = await db.tblUser.findAll({
attributes: ["user_id", "firstname", "lastname"],
include: [
{
model: db.tblVehicle,
attributes: [
"vin",
"year",
"make",
"model",
"trim",
"mileage",
"color",
"color_name",
"details",
],
include: [
{
model: db.tblOpportunity,
attributes: [],
where: {
auctioneer_id: auctioneerId,
week_id: parseInt(weekId),
},
raw: true,
},
{
model: db.tblVehicleRun,
attributes: [
"reserve",
"sale_status",
"sale_price",
"condition_light",
"announcements",
"auction_fee",
],
raw: true,
include: [
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
raw: true,
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
raw: true,
},
],
},
],
},
],
raw: true,
where: whereClause,
},
],
order: [[db.tblVehicle, sortBy || "vehicle_id", orderDirection || "ASC"]],
});
// Format the result as needed
const formattedData = result.map((user) => ({
user_id: user.user_id,
firstname: user.firstname,
lastname: user.lastname,
tblVehicles: user.tblVehicles.map((vehicle) => ({
vin: vehicle.vin,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
trim: vehicle.trim,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name,
details: vehicle.details,
reserve: vehicle.tblVehicleRuns[0].reserve,
sale_status: vehicle.tblVehicleRuns[0].sale_status,
sale_price: vehicle.tblVehicleRuns[0].sale_price,
condition_light: vehicle.tblVehicleRuns[0].condition_light,
announcements: vehicle.tblVehicleRuns[0].announcements,
auction_fee: vehicle.tblVehicleRuns[0].auction_fee,
lane_id: vehicle.tblVehicleRuns[0].tblAuctionLane.lane_id,
lane_name: vehicle.tblVehicleRuns[0].tblAuctionLane.name,
auction_name: vehicle.tblVehicleRuns[0].tblAuctionLane.tblAuction.name,
})),
}));
return res.json({ status: 200, message: "Success", data: formattedData });
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const filterByConditionLight = async (req, res) => {
try {
const { auctioneerId, weekId } = req.body;
const auctioneer_id = auctioneerId;
const week_id = weekId;
let result = await db.sequelize.query(
"CALL aFilterByConditionLight(:auctioneer_id,:week_id)",
{
replacements: { auctioneer_id, week_id },
type: db.Sequelize.QueryTypes.SELECT,
}
);
let data = result[0];
const formattedData = Object.values(data)
.flat()
.filter(
(item) => typeof item === "object" && !item.hasOwnProperty("fieldCount")
);
// return res.json(formattedData);
const conditionLightValues = [0, 1, 2, 3, 4];
// Check for missing condition_light values
const missingValues = conditionLightValues.filter((value) => {
return !formattedData.some((item) => item.condition_light === value);
});
// Add missing values to the existing data
const newData = formattedData.concat(
missingValues.map((value) => ({
condition_light: value,
units: 0,
}))
);
const filteredData = newData.filter((item) => item.condition_light != 0);
// # Sorting the list in-place in ascending order of 'condition_light'
filteredData.sort((a, b) => a.condition_light - b.condition_light);
return res.json({
status: 200,
message: "Success",
filter_type: "condition_light",
data: filteredData,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const getConditionLightVehicles = async (req, res) => {
try {
const { condition_light, auctioneer_id, week_id, sortBy, orderDirection } =
req.body;
let result;
result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: { auctioneer_id, week_id },
include: [
{
model: db.tblVehicleRun,
// required: true, // Use this instead of raw to ensure an INNER JOIN
where: { condition_light: condition_light },
include: [
{
model: db.tblVehicle,
// required: true, // Use this instead of raw to ensure an INNER JOIN
},
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
// required: true, // Use this instead of raw to ensure an INNER JOIN
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
// required: true, // Use this instead of raw to ensure an INNER JOIN
},
],
},
],
},
],
order: [
// Include the nested order here instead
[db.tblVehicleRun, db.tblVehicle, sortBy, orderDirection],
],
});
if (result.length <= 0) {
return res.json({ status: 200, message: "Success", data: [] });
}
// // Format the result as per the required format
const formattedResult = result.flatMap((item) =>
item.tblVehicleRuns.map((vehicleRun) => {
const vehicle = vehicleRun.tblVehicle || {};
const auctionLane = vehicleRun.tblAuctionLane || {};
const auction = auctionLane.tblAuction || {};
return {
vehicle_id: vehicle.vehicle_id,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
vin: vehicle.vin,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name,
details: vehicle.details,
condition_light: vehicleRun?.condition_light || 4,
sale_price: vehicleRun?.sale_price || 0,
run_no: vehicleRun?.run_no || null,
sale_status: vehicleRun?.sale_status || false,
lane_id: vehicleRun?.lane_id || null,
auction_fee: vehicleRun?.auction_fee || 300,
net_proceeds: vehicleRun?.net_proceeds || null,
vehicle_total_fee: vehicleRun?.vehicle_total_fee || 0,
reserve: vehicleRun?.reserve || 0,
lane_name: auctionLane?.name || null,
auction_id: auction?.auction_id || null,
auction_name: auction?.name || null,
};
})
);
return res.json({ status: 200, message: "Success", data: formattedResult });
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const filterBySaleStatus = async (req, res) => {
try {
const { auctioneerId, weekId } = req.body;
const auctioneer_id = auctioneerId;
const week_id = weekId;
let result = await db.sequelize.query(
"CALL aFilterBySaleStatus(:auctioneer_id,:week_id)",
{
replacements: { auctioneer_id, week_id },
type: db.Sequelize.QueryTypes.SELECT,
}
);
let data = result[0];
const formattedData = Object.values(data)
.flat()
.filter(
(item) => typeof item === "object" && !item.hasOwnProperty("fieldCount")
);
const saleStatusValues = ["true", "false"];
// Initialize newData with default objects if existingData is empty
let newData = [];
if (result.length === 0) {
newData = saleStatusValues.map((value) => ({
opportunity_id: 0,
auctioneer_id: 0,
sale_status: value,
units: 0,
}));
return res.json({
status: 200,
message: "Success",
data: newData,
});
}
const missingValues = saleStatusValues.filter((value) => {
return !formattedData.some((item) => item.sale_status === value);
});
// Add missing values to the existing data
newData = formattedData.concat(
missingValues.map((value) => ({
sale_status: value,
units: 0,
}))
);
return res.json({
status: 200,
message: "Success",
filter_type: "sale_status",
data: newData,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const getSaleStatusVehicles = async (req, res) => {
try {
const { sale_status, auctioneer_id, week_id, sortBy, orderDirection } =
req.body;
let result;
result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: { auctioneer_id, week_id },
include: [
{
model: db.tblVehicleRun,
// required: true, // Use this instead of raw to ensure an INNER JOIN
where: { sale_status: sale_status },
include: [
{
model: db.tblVehicle,
// required: true, // Use this instead of raw to ensure an INNER JOIN
},
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
required: false, // Use this instead of raw to ensure an INNER JOIN
where: { auctioneer_id: auctioneer_id },
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
// required: true, // Use this instead of raw to ensure an INNER JOIN
},
],
},
],
},
],
order: [
// Include the nested order here instead
[db.tblVehicleRun, db.tblVehicle, sortBy, orderDirection],
],
});
// return res.json(result);
if (result.length <= 0) {
return res.json({ status: 200, message: "Success", data: [] });
}
// // Format the result as per the required format
const formattedResult = result.flatMap((item) =>
item.tblVehicleRuns.map((vehicleRun) => {
const vehicle = vehicleRun.tblVehicle || {};
const auctionLane = vehicleRun.tblAuctionLane || {};
const auction = auctionLane.tblAuction || {};
return {
vehicle_id: vehicle.vehicle_id,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
vin: vehicle.vin,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name,
details: vehicle.details,
condition_light: vehicleRun?.condition_light || 4,
sale_price: vehicleRun?.sale_price || 0,
run_no: vehicleRun?.run_no || null,
sale_status: vehicleRun?.sale_status || false,
lane_id: vehicleRun?.lane_id || null,
auction_fee: vehicleRun?.auction_fee || 300,
net_proceeds: vehicleRun?.net_proceeds || null,
vehicle_total_fee: vehicleRun?.vehicle_total_fee || 0,
reserve: vehicleRun?.reserve || 0,
lane_name: auctionLane?.name || null,
auction_id: auction?.auction_id || null,
auction_name: auction?.name || null,
};
})
);
return res.json({ status: 200, message: "Success", data: formattedResult });
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const filterByAuctioneerAuctions = async (req, res) => {
try {
//let auctioneerId=req.user.auctioneer_id
const { auctioneerId, weekId } = req.body;
const auctioneer_id = auctioneerId;
const week_id = weekId;
let results = await db.sequelize.query(
"CALL aFilterByAuction(:auctioneer_id,:week_id)",
{
replacements: { auctioneer_id, week_id },
}
);
let [unCatogrizedResult] = await db.sequelize.query(
"CALL aAucUncatUnitCount(:auctioneer_id, :week_id)",
{
replacements: { auctioneer_id, week_id },
}
);
if (!unCatogrizedResult) {
unCatogrizedResult = {
auction_id: 0,
auction_name: "Not Provided",
units: 0,
};
}
results.push(unCatogrizedResult);
// Returning the result as a response
return res.json({
status: 200,
message: "Success",
filter_type: "auction",
data: results,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const GetVehicleCountBySaleStatus = async (req, res) => {
try {
const { auctioneerId, weekId } = req.body;
// Find user_ids from tblOpportunity based on auctioneerId and weekId
const userOpportunityIds = await db.tblOpportunity.findAll({
attributes: ["user_id"],
where: {
auctioneer_id: auctioneerId,
week_id: parseInt(weekId),
},
raw: true,
});
// Extract user_ids from the result
const userIds = userOpportunityIds.map(
(opportunity) => opportunity.user_id
);
// Find user data from tblUser and tblVehicle based on the obtained user_ids
const result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: {
week_id: weekId,
auctioneer_id: auctioneerId,
},
include: [
{
model: db.tblUser,
attributes: ["user_id", "firstname", "lastname"],
},
{
model: db.tblVehicleRun,
include: [
{
model: db.tblVehicle,
},
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
},
],
},
],
},
],
});
// return res.json(result);
const modifiedData = result.map((item) => {
return {
user_id: item.tblUser.user_id,
firstname: item.tblUser.firstname,
lastname: item.tblUser.lastname,
sold_vehicles: item.tblVehicleRuns
.filter((run) => run.sale_status === true)
.map((run) => {
const vehicle = run.tblVehicle;
return {
vehicle_id: vehicle.vehicle_id,
vin: vehicle.vin,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
trim: vehicle.trim,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name,
details: vehicle.details,
reserve: run.reserve,
sale_status: run.sale_status,
sale_price: run.sale_price,
condition_light: run.condition_light,
announcements: run.announcements,
auction_fee: run.vehicle_total_fee, // Assuming auction_fee refers to 'vehicle_total_fee' field.
run_no: run.run_no,
lane_id: run.tblAuctionLane.lane_id,
lane_name: run.tblAuctionLane.name,
auction_name: run.tblAuctionLane.tblAuction.name,
};
}),
not_sold_vehicles: item.tblVehicleRuns
.filter((run) => run.sale_status === false)
.map((run) => {
const vehicle = run.tblVehicle;
return {
vin: vehicle.vin,
year: vehicle.year,
make: vehicle.make,
model: vehicle.model,
trim: vehicle.trim,
mileage: vehicle.mileage,
color: vehicle.color,
color_name: vehicle.color_name,
details: vehicle.details,
reserve: run.reserve,
sale_status: run.sale_status,
sale_price: run.sale_price,
condition_light: run.condition_light,
announcements: run.announcements,
auction_fee: run.vehicle_total_fee, // Assuming auction_fee refers to 'vehicle_total_fee' field.
run_no: run.run_no,
lane_id: run.tblAuctionLane ? run.tblAuctionLane.lane_id : null,
lane_name: run.tblAuctionLane ? run.tblAuctionLane.name : null,
auction_name: run.tblAuctionLane
? run.tblAuctionLane.tblAuction.name
: null,
};
}),
};
});
return res.json({
status: 200,
message: "Success",
data: modifiedData,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const GetVehicleCountByAuction = async (req, res) => {
try {
const { auctioneerId, weekId } = req.body;
// Find user_ids from tblOpportunity based on auctioneerId and weekId
const userOpportunityIds = await db.tblOpportunity.findAll({
attributes: ["user_id"],
where: {
auctioneer_id: auctioneerId,
week_id: parseInt(weekId),
},
raw: true,
});
// Extract user_ids from the result
const userIds = userOpportunityIds.map(
(opportunity) => opportunity.user_id
);
// Find user data from tblUser and tblVehicle based on the obtained user_ids
const [result] = await db.sequelize.query(`
SELECT
o.opportunity_id,
auc.auction_id as auction_id,
auc.name as auction_name,
v.vin,
v.year,
v.make,
v.model,
al.lane_id,
al.name as lane_name,
vr.announcements,
vr.condition_light,
vr.sale_price,
vr.sale_status
from tblopportunities as o
inner join tblauctioneers as a on a.auctioneer_id=o.auctioneer_id
inner join tblauctionlanes as al on al.auctioneer_id=a.auctioneer_id
inner join tblauctions as auc on auc.auction_id=al.auction_id
inner join tblvehicleruns as vr on vr.lane_id=al.lane_id
inner join tblvehicles as v on v.vehicle_id=vr.vehicle_id
where o.auctioneer_id=${auctioneerId} and o.week_id=${weekId};`);
const groupByAuctionID = (data) => {
return data.reduce((acc, currentValue) => {
// Find an auction in the accumulator array.
let auction = acc.find((a) => a.auction_id === currentValue.auction_id);
// If the auction doesn't exist, create it and push it to the accumulator.
if (!auction) {
auction = {
auction_id: currentValue.auction_id,
auction_name: currentValue.auction_name,
data: [],
};
acc.push(auction);
}
// Add the current value to the data array of the found/created auction.
auction.data.push({
opportunity_id: currentValue.opportunity_id,
vin: currentValue.vin.trim(),
year: currentValue.year,
make: currentValue.make.trim(),
model: currentValue.model.trim(),
lane_id: currentValue.lane_id,
lane_name: currentValue.lane_name,
announcements: currentValue.announcements,
condition_light: currentValue.condition_light,
sale_price: currentValue.sale_price,
sale_status: currentValue.sale_status,
});
return acc;
}, []);
};
const transformedData = groupByAuctionID(result);
return res.json({
status: 200,
message: "Success",
data: transformedData,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const GetVehicleCountByConditionLight = async (req, res) => {
try {
const { auctioneerId, weekId } = req.body;
// Find user_ids from tblOpportunity based on auctioneerId and weekId
const userOpportunityIds = await db.tblOpportunity.findAll({
attributes: ["user_id"],
where: {
auctioneer_id: auctioneerId,
week_id: parseInt(weekId),
},
raw: true,
});
// Extract user_ids from the result
const userIds = userOpportunityIds.map(
(opportunity) => opportunity.user_id
);
// Find user data from tblUser and tblVehicle based on the obtained user_ids
const result = await db.tblOpportunity.findAll({
attributes: ["opportunity_id"],
where: {
week_id: weekId,
auctioneer_id: auctioneerId,
},
include: [
{
model: db.tblUser,
attributes: ["user_id", "firstname", "lastname"],
},
{
model: db.tblVehicleRun,
include: [
{
model: db.tblVehicle,
},
{
model: db.tblAuctionLane,
attributes: ["lane_id", "name"],
include: [
{
model: db.tblAuction,
attributes: ["auction_id", "name"],
},
],
},
],
},
],
});
const modifiedData = result.map((opportunity) => {
const { tblUser, tblVehicleRuns } = opportunity;
// Helper function to get vehicles based on condition light
const getVehiclesByConditionLight = (conditionLightValue) =>
tblVehicleRuns
.filter((run) => run.condition_light === conditionLightValue)
.map((run) => {
const { tblVehicle, tblAuctionLane } = run;
return {
vin: tblVehicle.vin,
year: tblVehicle.year,
make: tblVehicle.make,
model: tblVehicle.model,
mileage: tblVehicle.mileage,
trim: tblVehicle.trim,
condition_light: run.condition_light,
reserve: run.reserve,
announcements: run.announcements,
sale_price: run.sale_price,
sale_status: run.sale_status,
auction_fee: run.vehicle_total_fee,
lane_id: tblAuctionLane ? tblAuctionLane.lane_id : null,
lane_name: tblAuctionLane ? tblAuctionLane.name : null,
auction_name:
tblAuctionLane && tblAuctionLane.tblAuction
? tblAuctionLane.tblAuction.name
: null,
};
});
// Use the helper function for different condition lights
const redVehicles = getVehiclesByConditionLight(1); // Red condition light vehicles
const yellowVehicles = getVehiclesByConditionLight(2); // Yellow condition light vehicles
const greenVehicles = getVehiclesByConditionLight(3); // Green condition light vehicles
return {
user_id: tblUser.user_id,
firstname: tblUser.firstname,
lastname: tblUser.lastname,
red_vehicles: redVehicles,
yellow_vehicles: yellowVehicles,
green_vehicles: greenVehicles,
};
});
return res.json({
status: 200,
message: "Success",
data: modifiedData,
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
const auctioneerTotalSaleAndNetProceed = async (req, res) => {
try {
let { timeRange = "currentweek", auctioneer_id } = req.body;
const in_auctioneer_id = auctioneer_id;
timeRange = formatTimeRange(timeRange);
const weekRange = calculateDateRange(timeRange);
const start_date = weekRange.startDate;
const end_date = weekRange.endDate;
let [result] = await db.sequelize.query(
"CALL AuctioneerStats(:auctioneer_id,:start_date,:end_date)",
{
replacements: { auctioneer_id, start_date, end_date },
}
);
if (!result) {
return res.json({
status: 200,
message: "success",
data: {
sold_units: 0,
total_sales: 0,
net_proceeds: 0,
},
});
}
return res.json({
status: 200,
message: "success",
data: {
sold_units: result.sold_units || 0,
total_sales: result.total_sales || 0,
net_proceeds: result.net_proceeds || 0,
},
});
} catch (error) {
return res.status(500).json({
status: 500,
message: "Internal Server Error",
error: error.message,
});
}
};
module.exports = {
auctioneerLogin,
forgotPassword,
resetPasswordViaToken,
getAuctioneerProfile,
removeAuctioneer,
updateAuctioneerPassword,
GetAuctioneerUsers,
updateVehicleStatus,
updateAuctioneerProfile,
getAllAssignedVehicles,
sortAuctioneerVehicles,
filterByConditionLight,
filterBySaleStatus,
GetVehicleCountBySaleStatus,
GetVehicleCountByConditionLight,
GetAuctioneerUsersOnly,
getAllAssignedVehiclesOnly,
filterByAuctioneerAuctions,
auctioneerTotalSaleAndNetProceed,
getConditionLightVehicles,
getSaleStatusVehicles,
GetVehicleCountByAuction,
};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists