Sindbad~EG File Manager

Current Path : /home/infinitibizsol/.trash/controllers.4/
Upload File :
Current File : /home/infinitibizsol/.trash/controllers.4/auctioneerController.js

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