Skip to content

Commit

Permalink
Merge pull request #994 from IkkiOcean/backend-schema-11
Browse files Browse the repository at this point in the history
Backend Implementation for Delivery Person Management
  • Loading branch information
manikumarreddyu authored Nov 10, 2024
2 parents ba91e2a + 720ba3b commit d19f340
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 0 deletions.
269 changes: 269 additions & 0 deletions backend/controllers/shop/sub-controllers/deliveryPersonController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
const DeliveryPerson = require("../../../model/shop/sub-model/DeliveryPerson");
const { hashPassword } = require("../../../services/sub-service/hashPassword");
const {
validateEmail,
validatePhoneNumber,
} = require("../../../services/sub-service/couponValidator");

exports.successResponse = (res, statusCode, message, data = {}) => {
res.status(statusCode).json({
status: "success",
message,
data,
});
};

exports.errorResponse = (res, statusCode, message, error = {}) => {
res.status(statusCode).json({
status: "error",
message,
error,
});
};

// Create a new Delivery Person
exports.createDeliveryPerson = async (req, res) => {
try {
const {
name,
email,
phone_number,
status,
assigned_routes,
vehicle_details,
profile_picture,
password,
} = req.body;

// Validate required fields
if (!name || !email || !phone_number || !status) {
return errorResponse(res, 400, "All required fields must be provided.");
}

// Validate email and phone number formats
if (!validateEmail(email))
return errorResponse(res, 400, "Invalid email format.");
if (!validatePhoneNumber(phone_number))
return errorResponse(res, 400, "Invalid phone number format.");

// Check if email already exists
const existingEmail = await DeliveryPerson.findOne({ email });
if (existingEmail) return errorResponse(res, 400, "Email already exists.");

// Hash password if provided
const hashedPassword = password ? await hashPassword(password) : undefined;

const newDeliveryPerson = new DeliveryPerson({
name,
email,
phone_number,
status,
assigned_routes,
vehicle_details,
profile_picture,
password: hashedPassword,
});

await newDeliveryPerson.save();
successResponse(
res,
201,
"Delivery person created successfully.",
newDeliveryPerson
);
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Get all Delivery Persons with pagination
exports.getAllDeliveryPersons = async (req, res) => {
try {
const { page = 1, limit = 10 } = req.query;
const deliveryPersons = await DeliveryPerson.find()
.select("name status vehicle_details.vehicle_type")
.limit(parseInt(limit))
.skip((parseInt(page) - 1) * parseInt(limit));
const count = await DeliveryPerson.countDocuments();

successResponse(res, 200, "Delivery persons retrieved successfully.", {
deliveryPersons,
totalPages: Math.ceil(count / limit),
currentPage: parseInt(page),
});
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Get a Delivery Person by ID
exports.getDeliveryPersonById = async (req, res) => {
try {
const deliveryPerson = await DeliveryPerson.findById(
req.params.id
).populate("assigned_routes");
if (!deliveryPerson)
return errorResponse(res, 404, "Delivery person not found.");
successResponse(
res,
200,
"Delivery person retrieved successfully.",
deliveryPerson
);
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Update a Delivery Person
exports.updateDeliveryPerson = async (req, res) => {
try {
const updates = req.body;

// Validate and hash password if provided
if (updates.password)
updates.password = await hashPassword(updates.password);

// Validate email and phone number if updated
if (updates.email && !validateEmail(updates.email))
return errorResponse(res, 400, "Invalid email format.");
if (updates.phone_number && !validatePhoneNumber(updates.phone_number))
return errorResponse(res, 400, "Invalid phone number format.");

// Check if email already exists (excluding current delivery person)
if (updates.email) {
const existingEmail = await DeliveryPerson.findOne({
email: updates.email,
_id: { $ne: req.params.id },
});
if (existingEmail)
return errorResponse(res, 400, "Email already exists.");
}

const updatedDeliveryPerson = await DeliveryPerson.findByIdAndUpdate(
req.params.id,
updates,
{ new: true }
);
if (!updatedDeliveryPerson)
return errorResponse(res, 404, "Delivery person not found.");
successResponse(
res,
200,
"Delivery person updated successfully.",
updatedDeliveryPerson
);
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Soft delete (deactivate) a Delivery Person
exports.deleteDeliveryPerson = async (req, res) => {
try {
const deliveryPerson = await DeliveryPerson.findById(req.params.id);
if (!deliveryPerson)
return errorResponse(res, 404, "Delivery person not found.");

deliveryPerson.status = "inactive";
await deliveryPerson.save();
successResponse(res, 200, "Delivery person deactivated successfully.");
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Activate or Deactivate Delivery Person
exports.toggleStatus = async (req, res) => {
try {
const { status } = req.body;
if (!["active", "inactive"].includes(status))
return errorResponse(res, 400, "Invalid status.");

const deliveryPerson = await DeliveryPerson.findById(req.params.id);
if (!deliveryPerson)
return errorResponse(res, 404, "Delivery person not found.");

deliveryPerson.status = status;
await deliveryPerson.save();
successResponse(res, 200, "Delivery person status updated successfully.", {
status: deliveryPerson.status,
});
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Helper functions for response handling
const validateVehicleDetails = (vehicleDetails) => {
const { vehicle_type, vehicle_number } = vehicleDetails;
if (vehicle_type && typeof vehicle_type !== "string") return false;
if (vehicle_number && typeof vehicle_number !== "string") return false;
return true;
};

// Search Delivery Person by name
exports.searchDeliveryPersonByName = async (req, res) => {
try {
const { name } = req.query;
const deliveryPersons = await DeliveryPerson.find({
name: { $regex: name, $options: "i" },
});
successResponse(
res,
200,
"Search results retrieved successfully.",
deliveryPersons
);
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Get all assigned routes for a Delivery Person
exports.getAssignedRoutes = async (req, res) => {
try {
const deliveryPerson = await DeliveryPerson.findById(
req.params.id
).populate("assigned_routes");
if (!deliveryPerson)
return errorResponse(res, 404, "Delivery person not found.");
successResponse(
res,
200,
"Assigned routes retrieved successfully.",
deliveryPerson.assigned_routes
);
} catch (error) {
errorResponse(res, 500, error.message);
}
};

// Change Delivery Person's vehicle details
exports.updateVehicleDetails = async (req, res) => {
try {
const { vehicle_details } = req.body;

// Validate vehicle details format
if (vehicle_details && !validateVehicleDetails(vehicle_details)) {
return errorResponse(res, 400, "Invalid vehicle details format.");
}

const updatedDeliveryPerson = await DeliveryPerson.findByIdAndUpdate(
req.params.id,
{ vehicle_details },
{ new: true }
);

if (!updatedDeliveryPerson)
return errorResponse(res, 404, "Delivery person not found.");
successResponse(
res,
200,
"Vehicle details updated successfully.",
updatedDeliveryPerson.vehicle_details
);
} catch (error) {
errorResponse(res, 500, error.message);
}
};
15 changes: 15 additions & 0 deletions backend/middleware/sub-ware/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

const { check, validationResult } = require('express-validator');

exports.validateDeliveryPerson = [
check('email').isEmail().withMessage('Email is invalid'),
check('phone_number').isMobilePhone().withMessage('Phone number is invalid'),
check('status').isIn(['active', 'inactive']).withMessage('Status must be active or inactive'),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
44 changes: 44 additions & 0 deletions backend/model/shop/sub-model/DeliveryPerson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// models/DeliveryPerson.js
const mongoose = require("mongoose");

const deliveryPersonSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
phone_number: {
type: String,
required: true,
},
status: {
type: String,
enum: ["active", "inactive"],
required: true,
},
assigned_routes: [{ type: mongoose.Schema.Types.ObjectId, ref: "Route" }],
vehicle_details: {
vehicle_type: { type: String },
vehicle_number: { type: String },
},
created_at: {
type: Date,
default: Date.now,
},
updated_at: {
type: Date,
default: Date.now,
},
password: {
type: String
},
profile_picture: {
type: String
},
});

module.exports = mongoose.model("DeliveryPerson", deliveryPersonSchema);
9 changes: 9 additions & 0 deletions backend/services/sub-service/hashPassword.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

const bcrypt = require('bcrypt');

const hashPassword = async (password) => {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
};

module.exports = { hashPassword };

0 comments on commit d19f340

Please sign in to comment.