You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2483 lines
77 KiB

//Get the data models
const { Supplier, DeliveryBoy, profilePictureSupplier } = require("../models/supplier");
const { FriendRequest,RequestedBooking,RecurringRequestedBooking } = require("../models/supplier");
const { Tanker,Tankerbooking } = require("../models/tankers");
const { ProfilePicture, User } = require("../models/User");
const supplierController = require("../controllers/supplierController");
const customJwtAuth = require("../customAuthJwt");
const fastify = require("fastify")({
logger: true,
//disableRequestLogging: true,
genReqId(req) {
// you get access to the req here if you need it - must be a synchronous function
return uuidv4();
},
});
const moment = require('moment');
const fastifyEnv = require("fastify-env");
const boom = require("boom");
const emailValidator = require("email-validator");
const libphonenumberjs = require("libphonenumber-js");
fastify.register(customJwtAuth);
const schema = {
type: "object",
required: ["PORT"],
properties: {
PORT: {
type: "string",
default: 3000,
},
APIVERSION: {
type: "string",
default: "1.0.0",
},
},
};
const options = {
confKey: "config", // optional, default: 'config'
schema: schema,
// data: data // optional, default: process.env
};
fastify.register(fastifyEnv, options).ready((err) => {
if (err) console.error(err);
console.log(fastify.config.PORT); // or fastify[options.confKey]
// output: { PORT: 3000 }
fastify.decorate("conf", {
port: fastify.config.PORT,
APIVERSION: fastify.config.APIVERSION,
});
});
const apiversion = "1.0.0";
// fastify.register(require('fastify-cookie'))
// fastify.register(require('fastify-session'), {
// secret: 'my-secret-key',
// cookie: { secure: true }
// });
isSupplierFormUrlEncoded = (req) => {
var isSupplierFormUrlEncoded = false;
console.log("check is Supplier encoe url funtion");
// This iterates through the req headers object.
// could not access req.headers.content-type due to the hyphen in the content-type key.
// console.log(`${key}: ${value}`);
for (const [key, value] of Object.entries(req.headers)) {
if (`${key}` === "content-type") {
if (`${value}` == "application/x-www-form-urlencoded") {
// console.log( "data supplied is with content type," , `${value}`)
// set isUserFormUrlEncoded value to true
isSupplierFormUrlEncoded = true;
// create user object with form variables . Password is used from the request object directly.
s_data = {
suppliername: req.body.suppliername,
phone: req.body.phone,
office_address: req.body.office_address,
password: req.body.password,
emails: [
{
email: req.body.email,
},
],
profile: {
firstName: req.body.firstName,
lastName: req.body.lastName,
},
};
return {
isSupplierFormUrlEncoded: isSupplierFormUrlEncoded,
supplier: s_data,
};
} else {
return { isSupplierFormUrlEncoded: false, s_data: "" };
}
}
}
};
fastify.register((fastify, opts, done) => {
fastify.addContentTypeParser(
"application/json",
{ parseAs: "buffer" },
function (_req, body, done) {
try {
done(null, body);
} catch (error) {
error.statusCode = 400;
done(error, undefined);
}
}
);
done(null);
});
//Login Supplier Handler
exports.loginSupplier = async (request, reply) => {
loginObject = await supplierController.loginSupplier(request);
console.log("loginObject...", loginObject);
if (loginObject.same) {
const phoneVerified = loginObject.supplier.phoneVerified;
const oneTimePasswordSetFlag = loginObject.supplier.oneTimePasswordSetFlag;
console.log(
"oneTimePasswordSetFlag is ......",
oneTimePasswordSetFlag,
typeof oneTimePasswordSetFlag,
typeof phoneVerified
);
if (!phoneVerified) {
reply.send({
simplydata: {
error: false,
phoneVerified: false,
phone: loginObject.supplier.phone,
oneTimePasswordSetFlag: oneTimePasswordSetFlag,
message: "Please Verify your phone number",
},
});
} else if (oneTimePasswordSetFlag) {
reply.send({
simplydata: {
error: false,
phoneVerified: phoneVerified,
phone: loginObject.supplier.phone,
oneTimePasswordSetFlag: true,
message: "Password must be reset",
},
});
} else {
const token = fastify.jwt.sign(
{
suppliername: loginObject.supplier.suppliername,
supplierId: loginObject.supplier._id,
roles: loginObject.supplier.profile.role,
},
//expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d".
//A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc),
//otherwise milliseconds unit is used by default ("120" is equal to "120ms").
{ expiresIn: "30d" }
);
console.log(token, "..token");
var arr = loginObject.supplier.profile.role;
var arrayToString = JSON.stringify(Object.assign({}, arr)); // convert array to string
var stringToJsonObject = JSON.parse(arrayToString); // convert string to json object
var s_id = loginObject.supplier.supplierId;
console.log(s_id, "supplierId");
var profilePicture = await profilePictureSupplier.findOne({ supplierId: s_id });
// request.session.set('supplierId', loginObject.supplier._id)
if (!profilePicture) {
reply.send({
simplydata: {
error: false,
apiversion: fastify.config.APIVERSION,
access_token: token,
email: loginObject.supplier.emails,
phone: loginObject.supplier.phone,
supplierId: loginObject.supplier.supplierId,
suppliername: loginObject.supplier.suppliername,
office_address: loginObject.supplier.profile.office_address,
phoneVerified: loginObject.supplier.phoneVerified,
oneTimePasswordSetFlag: loginObject.supplier.oneTimePasswordSetFlag,
latitude: loginObject.supplier.latitude,
longitude: loginObject.supplier.longitude,
type: loginObject.supplier.profile.role,
description : loginObject.supplier.description,
typeasobj: stringToJsonObject,
},
});
}
if (profilePicture) {
reply.send({
simplydata: {
error: false,
apiversion: fastify.config.APIVERSION,
access_token: token,
picture: profilePicture.picture,
email: loginObject.supplier.emails,
phone: loginObject.supplier.phone,
supplierId: loginObject.supplier.supplierId,
suppliername: loginObject.supplier.suppliername,
office_address: loginObject.supplier.profile.office_address,
phoneVerified: loginObject.supplier.phoneVerified,
oneTimePasswordSetFlag: loginObject.supplier.oneTimePasswordSetFlag,
latitude: loginObject.supplier.latitude,
longitude: loginObject.supplier.longitude,
description : loginObject.supplier.description,
type: loginObject.supplier.profile.role,
typeasobj: stringToJsonObject,
},
});
}
}
} else {
error = {
simplydata: {
error: true,
code: 400,
message: "Invalid SupplierId , Password supplied",
},
};
reply.send(error);
}
};
//Login Delivery Handler
exports.loginDeliveryBoy = async (request, reply) => {
phone = request.body.phone;
phoneVerificationCode = request.body.phoneVerificationCode;
// check if user exists in the system. If user exists , display message that
// username is not available
console.log(
"this is the phone and verification code",
phone,
phoneVerificationCode
);
deliveryBoyExists = await DeliveryBoy.findOne({
phone: phone,
phoneVerified: false,
phoneVerificationCode: phoneVerificationCode,
});
console.log(deliveryBoyExists);
if (deliveryBoyExists) {
// update the phoneVerified flag to true.
const filter = {
phone: phone,
phoneVerificationCode: phoneVerificationCode,
};
const update = { phoneVerified: true };
const doc = await DeliveryBoy.findOneAndUpdate(filter, update);
updatedDeliveryBoy = await DeliveryBoy.findOne({ phone: phone });
}
loginObject = await supplierController.loginDeliveryBoy(request);
console.log("loginObject...", loginObject);
if (loginObject.same) {
const phoneVerified = loginObject.delivery.phoneVerified;
const oneTimePasswordSetFlag = loginObject.delivery.oneTimePasswordSetFlag;
console.log(
"oneTimePasswordSetFlag is ......",
oneTimePasswordSetFlag,
typeof oneTimePasswordSetFlag,
typeof phoneVerified
);
if (!phoneVerified) {
reply.send({
simplydata: {
error: false,
phoneVerified: false,
phone: loginObject.delivery.phone,
oneTimePasswordSetFlag: oneTimePasswordSetFlag,
message: "Please Verify your phone number",
},
});
} else if (oneTimePasswordSetFlag) {
reply.send({
simplydata: {
error: false,
phoneVerified: phoneVerified,
phone: loginObject.delivery.phone,
oneTimePasswordSetFlag: true,
message: "Password must be reset",
},
});
} else {
const token = fastify.jwt.sign(
{
deliveryBoyname: loginObject.delivery.name,
deliveryBoyId: loginObject.delivery._id,
},
//expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d".
//A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc),
//otherwise milliseconds unit is used by default ("120" is equal to "120ms").
{ expiresIn: "30d" }
);
console.log(token, "..token");
var d_id = loginObject.delivery._id;
console.log(d_id, "deliveryId");
var profilePicture = await ProfilePicture.findOne({
deliveryBoyId: d_id,
});
// request.session.set('supplierId', loginObject.supplier._id)
if (!profilePicture) {
reply.send({
simplydata: {
error: false,
apiversion: fastify.config.APIVERSION,
access_token: token,
phone: loginObject.delivery.phone,
deliveryBoyId: loginObject.delivery.deliveryBoyId,
deliveryBoyname: loginObject.delivery.name,
address: loginObject.delivery.address,
phoneVerified: loginObject.delivery.phoneVerified,
oneTimePasswordSetFlag: loginObject.delivery.oneTimePasswordSetFlag,
supplierId: loginObject.delivery.supplierId,
suppliername: loginObject.delivery.suppliername,
longitude: loginObject.delivery.longitude,
latitude: loginObject.delivery.latitude,
},
});
}
if (profilePicture) {
reply.send({
simplydata: {
error: false,
apiversion: fastify.config.APIVERSION,
access_token: token,
picture: profilePicture.picture,
phone: loginObject.delivery.phone,
deliveryBoyId: loginObject.delivery.deliveryBoyId,
deliveryBoyname: loginObject.delivery.name,
address: loginObject.delivery.address,
phoneVerified: loginObject.delivery.phoneVerified,
oneTimePasswordSetFlag: loginObject.delivery.oneTimePasswordSetFlag,
supplierId: loginObject.delivery.supplierId,
suppliername: loginObject.delivery.suppliername,
longitude: loginObject.delivery.longitude,
latitude: loginObject.delivery.latitude,
},
});
}
}
} else {
error = {
simplydata: {
error: true,
code: 400,
message: "Invalid Details",
},
};
reply.send(error);
}
};
exports.deliveryBoyVerifyPhone = async (req, reply) => {
console.log("-------------------------------------------------");
try {
phone = req.body.phone;
phoneVerificationCode = req.body.phoneVerificationCode;
// check if user exists in the system. If user exists , display message that
// username is not available
console.log(
"this is the phone and verification code",
phone,
phoneVerificationCode
);
deliveryBoyExists = await DeliveryBoy.findOne({
phone: phone,
//phoneVerified: false,
phoneVerificationCode: phoneVerificationCode,
});
console.log(deliveryBoyExists);
if (deliveryBoyExists) {
// update the phoneVerified flag to true.
const filter = {
phone: phone,
phoneVerificationCode: phoneVerificationCode,
};
const update = { phoneVerified: true };
const doc = await DeliveryBoy.findOneAndUpdate(filter, update);
updatedDeliveryBoy = await DeliveryBoy.findOne({ phone: phone });
if (updatedDeliveryBoy.phoneVerified) {
loginObject = await supplierController.loginDeliveryBoy(req);
console.log("loginObject...", loginObject);
if (loginObject.same) {
const phoneVerified = loginObject.delivery.phoneVerified;
const oneTimePasswordSetFlag =
loginObject.delivery.oneTimePasswordSetFlag;
console.log(
"oneTimePasswordSetFlag is ......",
oneTimePasswordSetFlag,
typeof oneTimePasswordSetFlag,
typeof phoneVerified
);
if (!phoneVerified) {
reply.send({
simplydata: {
error: false,
phoneVerified: false,
phone: loginObject.delivery.phone,
oneTimePasswordSetFlag: oneTimePasswordSetFlag,
message: "Please Verify your phone number",
},
});
} else if (oneTimePasswordSetFlag) {
reply.send({
simplydata: {
error: false,
phoneVerified: phoneVerified,
phone: loginObject.delivery.phone,
oneTimePasswordSetFlag: true,
message: "Password must be reset",
},
});
} else {
const token = fastify.jwt.sign(
{
deliveryBoyname: loginObject.delivery.name,
deliveryBoyId: loginObject.delivery._id,
},
//expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d".
//A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc),
//otherwise milliseconds unit is used by default ("120" is equal to "120ms").
{ expiresIn: "30d" }
);
console.log(token, "..token");
var d_id = loginObject.delivery._id;
console.log(d_id, "deliveryId");
var profilePicture = await ProfilePicture.findOne({
deliveryBoyId: d_id,
});
// request.session.set('supplierId', loginObject.supplier._id)
if (!profilePicture) {
reply.send({
simplydata: {
error: false,
apiversion: fastify.config.APIVERSION,
access_token: token,
phone: loginObject.delivery.phone,
deliveryBoyId: loginObject.delivery.deliveryBoyId,
deliveryBoyname: loginObject.delivery.name,
address: loginObject.delivery.address,
phoneVerified: loginObject.delivery.phoneVerified,
oneTimePasswordSetFlag:
loginObject.delivery.oneTimePasswordSetFlag,
supplierId: loginObject.delivery.supplierId,
suppliername: loginObject.delivery.suppliername,
longitude: loginObject.delivery.longitude,
latitude: loginObject.delivery.latitude,
},
});
}
if (profilePicture) {
reply.send({
simplydata: {
error: false,
apiversion: fastify.config.APIVERSION,
access_token: token,
picture: profilePicture.picture,
phone: loginObject.delivery.phone,
deliveryBoyId: loginObject.delivery.deliveryBoyId,
deliveryBoyname: loginObject.delivery.name,
address: loginObject.delivery.address,
phoneVerified: loginObject.delivery.phoneVerified,
oneTimePasswordSetFlag:
loginObject.delivery.oneTimePasswordSetFlag,
supplierId: loginObject.delivery.supplierId,
suppliername: loginObject.delivery.suppliername,
longitude: loginObject.delivery.longitude,
latitude: loginObject.delivery.latitude,
},
});
}
}
} else {
error = {
simplydata: {
error: true,
code: 400,
message: "Invalid Details",
},
};
reply.send(error);
}
}
}else {
error = {
armintatankdata: {
error: true,
code: 10005,
message: "10005 - Verification code entered cannot be validated.",
},
};
req.body.regError = error;
reply.send(error);
}
} catch (err) {
throw boom.boomify(err);
}
};
// Check if all the required fields are supplied by the user
exports.fieldCheck = async (req, reply) => {
try {
s_Data = {
suppliername: req.body.suppliername,
emails: req.body.emails,
password: req.body.password,
services: { password: { bcrypt: req.body.password } },
phone: req.body.phone,
profile: {
firstName: req.body.firstName,
lastName: req.body.lastName,
contactNumber: req.body.phone,
alternativeContactNumber: req.body.alternativeContactNumber,
country: req.body.country,
state: req.body.state,
city: req.body.city,
office_address: req.body.office_adress,
zip: req.body.zip,
},
};
var supplier = new Supplier(s_Data);
console.log(supplier, "..supplier");
//password is not at the top level in the collection.
password = req.body.password;
// capture fields if data is sent via form instead of json encoding
checkFormEncoding = isSupplierFormUrlEncoded(req);
if (checkFormEncoding.isSupplierFormUrlEncoded) {
suppliertobeInserted = checkFormEncoding.supplier;
supplier.suppliername = suppliertobeInserted.suppliername;
supplier.phone = suppliertobeInserted.phone;
supplier.emails = suppliertobeInserted.emails;
password = suppliertobeInserted.password;
}
console.log(
"User to be inserted is ",
supplier.suppliername,
password,
supplier.phone,
supplier.profile
);
// check if all rerquired fields are passed.
if (
!(
supplier.suppliername &&
password &&
supplier.phone &&
// user.profile.firstName &&
// user.profile.lastName &&
// user.profile.address1 &&
supplier.emails[0].email
)
) {
console.log(
supplier.suppliername,
password,
supplier.phone,
// user.profile.firstName,
// user.profile.lastName,
supplier.emails[0].email
);
// Required Fields are missing
suppliedvalues =
supplier.suppliername +
" ," +
password +
" ," +
supplier.phone +
" ," +
supplier.firstName +
" ," +
supplier.lastName +
" ," +
supplier.emails[0].email;
error = {
armintatankdata: {
error: true,
code: 10004,
message:
"10004 - suppliername, password, phone , firstname , lastname email city country state address1 and zip are required fields. Supplied values are " +
suppliedvalues,
},
};
req.body.regError = error;
reply.send(error);
}
} catch (err) {
throw boom.boomify(err);
}
};
exports.validatePhoneFormat = async (req, reply) => {
try {
var supplier = new Supplier(req.body);
// check if user supplied phone is of the right format.
// Handle if the user data is supplied via a url encoded form
// capture fields if data is sent via form instead of json encoding
checkFormEncoding = isSupplierFormUrlEncoded(req);
console.log(checkFormEncoding);
if (checkFormEncoding.isSupplierFormUrlEncoded) {
suppliertobeInserted = checkFormEncoding.supplier;
supplier.suppliername = suppliertobeInserted.suppliername;
supplierser.firstName = suppliertobeInserted.firstName;
supplier.lastName = suppliertobeInserted.lastName;
supplier.phone = suppliertobeInserted.phone;
supplier.emails = suppliertobeInserted.emails;
}
if (supplier) {
const phoneNumber = libphonenumberjs.parsePhoneNumber(supplier.phone);
if (phoneNumber) {
// access returned collection
if (!phoneNumber.isValid()) {
error = {
armintatankdata: {
error: true,
code: 10002,
message:
"10002 - Phone # " +
supplier.phone +
" is not a valid phone number",
},
};
req.body.regError = error;
reply.status(406).send(error);
}
}
}
} catch (err) {
throw boom.boomify(err);
}
};
exports.verifySupplier = async (req, reply) => {
try {
var supplier = new Supplier(req.body);
// Handle if the user data is supplied via a url encoded form
// capture fields if data is sent via form instead of json encoding
checkFormEncoding = isSupplierFormUrlEncoded(req);
if (checkFormEncoding.isSupplierFormUrlEncoded) {
suppliertobeInserted = checkFormEncoding.supplier;
supplier.suppliername = suppliertobeInserted.suppliername;
supplier.firstName = suppliertobeInserted.firstName;
supplier.lastName = suppliertobeInserted.lastName;
supplierr.phone = suppliertobeInserted.phone;
supplier.emails = suppliertobeInserted.emails;
}
phone = supplier.phone;
supplierpass = req.body.password;
// check if user exists in the system. If user exists , display message that
// phone number is not available
supplierExists = await Supplier.findOne({ phone: phone });
if (supplierExists) {
// return user exists message
error = {
armintatankdata: {
error: true,
code: 10001,
message:
"10001 - Phone " +
supplierExists.phone +
" is not available. please use a different phone number",
},
};
req.body.regError = error;
reply.send(error);
}
} catch (err) {
throw boom.boomify(err);
}
};
exports.validateEmailFormat = async (req, reply) => {
try {
var supplier = new Supplier(req.body);
// Handle if the user data is supplied via a url encoded form
// capture fields if data is sent via form instead of json encoding
checkFormEncoding = isSupplierFormUrlEncoded(req);
if (checkFormEncoding.isSupplierFormUrlEncoded) {
suppliertobeInserted = checkFormEncoding.supplier;
supplier.suppliername = suppliertobeInserted.suppliername;
supplier.firstName = suppliertobeInserted.firstName;
supplier.lastName = suppliertobeInserted.lastName;
supplierr.phone = suppliertobeInserted.phone;
supplier.emails = suppliertobeInserted.emails;
}
supplieremail = await supplier.emails[0].email;
// check if user supplied email is of the right format.
if (supplier) {
const isValidEmail = emailValidator.validate(supplieremail.trim());
if (!isValidEmail) {
// Return email invalid format message
error = {
armintatankdata: {
error: true,
code: 10003,
message:
"10003 - Email " +
supplier.emails[0].email +
" is not a valid email",
},
};
req.body.regError = error;
reply.send(error);
}
}
} catch (err) {
throw boom.boomify(err);
}
};
exports.logoutsupplier = async (request, reply) => {
// request.session.delete();
// // send response to clear token
// reply.send({ message: 'Successfully logged out' })
const invalidatedTokens = {};
const accessToken =
request.headers.authorization && request.body.access_token;
invalidatedTokens[accessToken] = true;
// // localStorage.removeItem(invalidatedTokens[accessToken])
reply.send({ message: "Logout successful" });
};
exports.verifyPhone = async (req, reply) => {
console.log("-------------------------------------------------");
try {
phone = req.body.phone;
phoneVerificationCode = req.body.phoneVerificationCode;
// check if user exists in the system. If user exists , display message that
// username is not available
console.log(
"this is the phone and verification code",
phone,
phoneVerificationCode
);
supplierExists = await Supplier.findOne({
phone: phone,
phoneVerified: false,
phoneVerificationCode: phoneVerificationCode,
});
console.log(supplierExists);
if (supplierExists) {
// update the phoneVerified flag to true.
const filter = {
phone: phone,
phoneVerificationCode: phoneVerificationCode,
};
const update = { phoneVerified: true };
const doc = await Supplier.findOneAndUpdate(filter, update);
updatedSupplier = await Supplier.findOne({ phone: phone });
if (updatedSupplier.phoneVerified) {
reply.send('{"armintatankdata":{"error":false,"verified": true}}');
} else {
error = {
armintatankdata: {
error: true,
code: 10005,
message: "10005 - Verification code entered cannot be validated.",
},
};
req.body.regError = error;
reply.send(error);
}
} else {
error = {
armintatankdata: {
error: true,
code: 10005,
message: "10005 - Verification code entered cannot be validated.",
},
};
req.body.regError = error;
reply.send(error);
}
} catch (err) {
throw boom.boomify(err);
}
};
// exports.deliveryBoyVerifyPhone = async (req, reply) => {
// console.log("-------------------------------------------------");
// try {
// phone = req.body.phone;
// phoneVerificationCode = req.body.phoneVerificationCode;
// // check if user exists in the system. If user exists , display message that
// // username is not available
// console.log(
// "this is the phone and verification code",
// phone,
// phoneVerificationCode
// );
// deliveryBoyExists = await DeliveryBoy.findOne({
// phone: phone,
// phoneVerified: false,
// phoneVerificationCode: phoneVerificationCode,
// });
// console.log(deliveryBoyExists);
// if (deliveryBoyExists) {
// // update the phoneVerified flag to true.
// const filter = {
// phone: phone,
// phoneVerificationCode: phoneVerificationCode,
// };
// const update = { phoneVerified: true };
// const doc = await DeliveryBoy.findOneAndUpdate(filter, update);
// updatedDeliveryBoy = await DeliveryBoy.findOne({ phone: phone });
// if (updatedDeliveryBoy.phoneVerified) {
// reply.send('{"armintatankdata":{"error":false,"verified": true}}');
// } else {
// error = {
// armintatankdata: {
// error: true,
// code: 10005,
// message: "10005 - Verification code entered cannot be validated.",
// },
// };
// req.body.regError = error;
// reply.send(error);
// }
// }
// } catch (err) {
// throw boom.boomify(err);
// }
// };
//delete selected deliveryboy
exports.deleteDeliveryBoy = async (req, reply) => {
try {
var supplierId = req.params.supplierId;
var phone = req.query.phone;
const delivery = await DeliveryBoy.findOneAndDelete({
phone: phone,
supplierId: supplierId,
});
reply.send({ status_code: 200, data: delivery });
// return tank;
} catch (err) {
throw boom.boomify(err);
}
};
//update selected Delivery Boy Details
exports.updateDeliveryBoy = async (req, reply) => {
try {
var supplierId = req.params.supplierId;
var phone = req.query.phone;
const delivery = req.body;
const { ...updateData } = delivery;
const update = await DeliveryBoy.findOneAndUpdate(
{ phone: phone, supplierId: supplierId },
updateData,
{ new: true }
);
console.log(update);
//return update;
reply.send({ status_code: 200, data: update });
} catch (err) {
throw boom.boomify(err);
}
};
// Get current supplier
exports.getCurrentSupplier = async (req, reply) => {
try {
const supplierId = req.body.supplierId;
const suppliers = await Supplier.findOne({ supplierId: supplierId });
return suppliers;
} catch (err) {
throw boom.boomify(err);
}
};
// Get all suppliers
// exports.getSuppliers = async (req, reply) => {
// const limit = parseInt(req.query.limit) || 100;
// const page = parseInt(req.query.page) || 1;
// const startindex = (page - 1) * limit;
// try {
// await Supplier.find()
// .limit(limit)
// .skip(startindex)
// .exec()
// .then((docs) => {
// reply.send({ status_code: 200, data: docs, count: docs.length });
// })
// .catch((err) => {
// console.log(err);
// reply.send({ error: err });
// });
// } catch (err) {
// throw boom.boomify(err);
// }
// };
exports.getSuppliers = async (req, reply) => {
const customerId = req.params.customerId;
const {
type_of_water,
capacity: requestedCapacityStr,
quantity: requestedQuantityStr,
date,
time,
price_from,
price_to,
radius_from,
radius_to,
rating_from,
rating_to
} = req.body;
const parseCapacity = (value) => parseFloat((value || "0").toString().replace(/,/g, ""));
const parsePrice = (value) => parseInt((value || "0").toString().replace(/,/g, ""));
const requestedCapacity = parseCapacity(requestedCapacityStr);
const requestedQuantity = parseInt(requestedQuantityStr || "0");
const totalRequiredCapacity = requestedCapacity * requestedQuantity;
const priceFrom = parsePrice(price_from);
const priceTo = parsePrice(price_to);
try {
const customerData = await User.findOne({ customerId });
const favorateSuppliers = customerData?.favorate_suppliers || [];
const tankerBookings = await Tankerbooking.find({ date });
const bookedTankerSet = new Set(
tankerBookings.map(booking => `${booking.supplierId}_${booking.tankerName}`)
);
const tankerQuery = {};
if (type_of_water && type_of_water.trim() !== "") {
tankerQuery.typeofwater = type_of_water;
}
let tankers = await Tanker.find(tankerQuery);
const isValidPrice = (val) => {
const num = parseInt(val);
return !isNaN(num) && isFinite(num);
};
if (isValidPrice(price_from) && isValidPrice(price_to)) {
tankers = tankers.filter(tanker => {
const tankerPrice = parsePrice(tanker.price);
return tankerPrice >= priceFrom && tankerPrice <= priceTo;
});
}
tankers = tankers.filter(tanker => {
const key = `${tanker.supplierId}_${tanker.tankerName}`;
return !bookedTankerSet.has(key);
});
const supplierTankerMap = {};
for (let tanker of tankers) {
if (!supplierTankerMap[tanker.supplierId]) {
supplierTankerMap[tanker.supplierId] = [];
}
supplierTankerMap[tanker.supplierId].push(tanker);
}
const qualifiedSuppliers = [];
for (let [supplierId, supplierTankers] of Object.entries(supplierTankerMap)) {
const totalAvailableCapacity = supplierTankers.reduce(
(sum, t) => sum + parseCapacity(t.capacity),
0
);
if (requestedCapacity > 0 && requestedQuantity > 0) {
if (totalAvailableCapacity < totalRequiredCapacity) {
continue;
}
}
qualifiedSuppliers.push({ supplierId, tankers: supplierTankers });
}
const suppliers = [];
for (let supplierObj of qualifiedSuppliers) {
const supplierData = await Supplier.findOne({ supplierId: supplierObj.supplierId });
const friendRequest = await FriendRequest.findOne({
customerId: customerId,
supplierId: supplierObj.supplierId
});
const isConnected = friendRequest && friendRequest.status === "accepted";
const isFavorite = favorateSuppliers.includes(supplierObj.supplierId);
// 🔥 Now check RequestedBooking collection
const requestedBookingRecord = await RequestedBooking.findOne({
customerId: customerId,
"requested_suppliers.supplierId": supplierObj.supplierId
});
let requestedBooking = { status: false };
if (requestedBookingRecord) {
requestedBooking = {
status: true,
time: requestedBookingRecord.time
};
}
suppliers.push({
supplier: supplierData,
tankers: supplierObj.tankers,
isConnected: isConnected,
isFavorite: isFavorite,
requestedBooking: requestedBooking
});
}
reply.send({
status_code: 200,
suppliers
});
} catch (err) {
console.error(err);
reply.send({
status_code: 500,
message: "Something went wrong",
error: err.message
});
}
};
// GET SUPPLIERS (simple): only needs customerId; no tanker checks
exports.getSupplierswithoutbooking = async (req, reply) => {
try {
const { customerId } = req.params;
// 1) Load customer to read favorites
const customer = await User.findOne({ customerId }, { favorate_suppliers: 1, _id: 0 });
if (!customer) {
return reply.code(404).send({ status_code: 404, message: "Customer not found" });
}
const favoriteSet = new Set(customer.favorate_suppliers || []);
// 2) Load all suppliers
const suppliers = await Supplier.find({}); // add projection if you want to slim payload
// 3) Find accepted connections for this customer across ALL suppliers in one go
const supplierIds = suppliers.map(s => s.supplierId).filter(Boolean);
const acceptedReqs = await FriendRequest.find(
{ customerId, supplierId: { $in: supplierIds }, status: "accepted" },
{ supplierId: 1, _id: 0 }
);
const connectedSet = new Set(acceptedReqs.map(r => r.supplierId));
// 4) Build response
const result = suppliers.map(s => ({
supplier: s,
isFavorite: favoriteSet.has(s.supplierId),
isConnected: connectedSet.has(s.supplierId),
}));
return reply.send({ status_code: 200, suppliers: result });
} catch (err) {
console.error(err);
return reply.code(500).send({
status_code: 500,
message: "Something went wrong",
error: err.message,
});
}
};
exports.createRequestedBooking = async (req, reply) => {
const {
customerId,
type_of_water,
capacity,
quantity,
date,
time,
requested_suppliers
} = req.body;
const parseCapacity = (value) => parseFloat((value || "0").toString().replace(/,/g, ""));
const requestedCapacity = parseCapacity(capacity);
const requestedQuantity = parseInt(quantity || "0");
const totalRequiredCapacity = requestedCapacity * requestedQuantity;
try {
const requestedBooking = new RequestedBooking({
customerId,
type_of_water,
capacity,
quantity,
total_required_capacity: totalRequiredCapacity,
date,
time,
requested_suppliers, // ✅ already contains supplierId, quoted_amount, custom_field
status: "pending"
});
await requestedBooking.save();
reply.send({
status_code: 200,
message: "Requested booking created successfully",
data: requestedBooking
});
} catch (err) {
console.error(err);
reply.send({
status_code: 500,
message: "Something went wrong while saving",
error: err.message
});
}
}
// Get single user by ID
exports.getSingleSupplier = async (req, reply) => {
try {
const supplierId = req.params.supplierId;
const supplier = await Supplier.findOne({ supplierId: supplierId });
return supplier;
} catch (err) {
throw boom.boomify(err);
}
};
// exports.getConnectedSuppliers = async (req, reply) => {
// const limit = parseInt(req.query.limit) || 100;
// const page = parseInt(req.query.page) || 1;
// const startindex = (page - 1) * limit;
// const customerId = req.params.customerId; // Assuming you have already authenticated the user and stored their ID in the request object
// try {
// const friendRequests = await FriendRequest.find({
// customerId,
// status: "accepted",
// });
// // console.log(friendRequests,customerId)
// const supplierIdsToInclude = friendRequests.map(
// (request) => request.supplierId
// );
// await Supplier.find({ supplierId: { $in: supplierIdsToInclude } })
// .limit(limit)
// .skip(startindex)
// .exec()
// .then((docs) => {
// reply.send({ status_code: 200, data: docs, count: docs.length });
// })
// .catch((err) => {
// console.log(err);
// reply.send({ error: err });
// });
// } catch (err) {
// throw boom.boomify(err);
// }
// };
exports.getConnectedSuppliers = async (req, reply) => {
const limit = parseInt(req.query.limit) || 100;
const page = parseInt(req.query.page) || 1;
const startindex = (page - 1) * limit;
const customerId = req.params.customerId;
try {
// Get user's favorite suppliers
const user = await User.findOne({ customerId }, 'favorate_suppliers');
const favorateSuppliers = user?.favorate_suppliers || [];
// Get accepted friend requests
const friendRequests = await FriendRequest.find({
customerId,
status: "accepted",
});
const supplierIdsToInclude = friendRequests.map(req => req.supplierId);
// Get suppliers
const suppliers = await Supplier.find({
supplierId: { $in: supplierIdsToInclude }
})
.limit(limit)
.skip(startindex)
.exec();
const supplierIds = suppliers.map(s => s.supplierId);
// Get profile pictures
const profilePictures = await profilePictureSupplier.find({
supplierId: { $in: supplierIds }
});
// Construct final response
const data = suppliers.map((supplier) => {
const profilePicture = profilePictures.find(
(pic) => pic.supplierId === supplier.supplierId
);
const isFavorate = favorateSuppliers.includes(supplier.supplierId);
return {
...supplier.toObject(),
picture: profilePicture ? profilePicture.picture : null,
favorate: isFavorate,
};
});
reply.send({ status_code: 200, data, count: data.length });
} catch (err) {
throw boom.boomify(err);
}
};
// exports.getPendingSuppliers = async (req, reply) => {
// const limit = parseInt(req.query.limit) || 100;
// const page = parseInt(req.query.page) || 1;
// const startindex = (page - 1) * limit;
// const customerId = req.params.customerId; // Assuming you have already authenticated the user and stored their ID in the request object
// try {
// const friendRequests = await FriendRequest.find({
// customerId,
// status: ["pending"],
// });
// // console.log(friendRequests,customerId)
// const supplierIdsToInclude = friendRequests.map(
// (request) => request.supplierId
// );
// console.log(supplierIdsToInclude, "SUPLIERINCLUDE");
// const timestamps = friendRequests.map(request => request.timestamp);
// console.log(timestamps, "timestamps");
// await Supplier.find({ supplierId: { $in: supplierIdsToInclude } })
// .limit(limit)
// .skip(startindex)
// .exec()
// .then((docs) => {
// const customerDataWithTimestamp = docs.map((doc, index) => ({
// ...doc._doc,
// timestamp: timestamps[index],
// }));
// reply.send({
// status_code: 200,
// data: customerDataWithTimestamp,
// count: docs.length,
// });
// //reply.send({ status_code: 200, data: docs, count: docs.length });
// })
// .catch((err) => {
// console.log(err);
// reply.send({ error: err });
// });
// } catch (err) {
// throw boom.boomify(err);
// }
// };
exports.getPendingSuppliers = async (req, reply) => {
const limit = parseInt(req.query.limit) || 100;
const page = parseInt(req.query.page) || 1;
const startindex = (page - 1) * limit;
const customerId = req.params.customerId; // Assuming you have already authenticated the user and stored their ID in the request object
try {
const friendRequests = await FriendRequest.find({
customerId,
status: ["pending"],
});
const supplierIdsToInclude = friendRequests.map(
(request) => request.supplierId
);
const timestamps = friendRequests.map((request) => request.timestamp);
const suppliers = await Supplier.find({
supplierId: { $in: supplierIdsToInclude },
})
.limit(limit)
.skip(startindex)
.exec();
const supplierIds = suppliers.map((supplier) => supplier.supplierId);
const profilePictures = await profilePictureSupplier.find({
supplierId: { $in: supplierIds },
}).exec();
const data = suppliers.map((supplier, index) => {
const profilePicture = profilePictures.find(
(picture) => picture.supplierId === supplier.supplierId
);
return {
...supplier.toObject(),
timestamp: timestamps[index],
picture: profilePicture ? profilePicture.picture : null,
};
});
reply.send({ status_code: 200, data, count: data.length });
} catch (err) {
throw boom.boomify(err);
}
};
// exports.getRejectSuppliers = async (req, reply) => {
// const limit = parseInt(req.query.limit) || 100;
// const page = parseInt(req.query.page) || 1;
// const startindex = (page - 1) * limit;
// const customerId = req.params.customerId; // Assuming you have already authenticated the user and stored their ID in the request object
// try {
// const friendRequests = await FriendRequest.find({
// customerId,
// status: ["rejected"],
// });
// // console.log(friendRequests,customerId)
// const supplierIdsToInclude = friendRequests.map(
// (request) => request.supplierId
// );
// // console.log(supplierIdsToInclude)
// await Supplier.find({ supplierId: { $in: supplierIdsToInclude } })
// .limit(limit)
// .skip(startindex)
// .exec()
// .then((docs) => {
// reply.send({ status_code: 200, data: docs, count: docs.length });
// })
// .catch((err) => {
// console.log(err);
// reply.send({ error: err });
// });
// } catch (err) {
// throw boom.boomify(err);
// }
// };
exports.getRejectSuppliers = async (req, reply) => {
const limit = parseInt(req.query.limit) || 100;
const page = parseInt(req.query.page) || 1;
const startindex = (page - 1) * limit;
const customerId = req.params.customerId; // Assuming you have already authenticated the user and stored their ID in the request object
try {
const friendRequests = await FriendRequest.find({
customerId,
status: ["rejected"],
});
const supplierIdsToInclude = friendRequests.map(
(request) => request.supplierId
);
const suppliers = await Supplier.find({
supplierId: { $in: supplierIdsToInclude },
})
.limit(limit)
.skip(startindex)
.exec();
const supplierIds = suppliers.map((supplier) => supplier.supplierId);
const profilePictures = await profilePictureSupplier.find({
supplierId: { $in: supplierIds },
}).exec();
const data = suppliers.map((supplier) => {
const profilePicture = profilePictures.find(
(picture) => picture.supplierId === supplier.supplierId
);
return {
...supplier.toObject(),
picture: profilePicture ? profilePicture.picture : null,
};
});
reply.send({ status_code: 200, data, count: data.length });
} catch (err) {
throw boom.boomify(err);
}
};
exports.getPendingCustomers = async (req, reply) => {
const limit = parseInt(req.query.limit) || 100;
const page = parseInt(req.query.page) || 1;
const startindex = (page - 1) * limit;
const supplierId = req.params.supplierId;
try {
const friendRequests = await FriendRequest.find({
supplierId,
status: ["pending"],
});
const supplierIdsToInclude = friendRequests.map(
(request) => request.customerId
);
// const timestamps = friendRequests.map(request =>
// moment(request.timestamp, "DD-MM-YYYYTHH:mm:ss.SSSZ").format("DD-MM-YYYY hh:mm:ss")
// );
const timestamps = friendRequests.map(request => request.timestamp);
console.log(timestamps, "timestamps");
await User.find({ customerId: { $in: supplierIdsToInclude } })
.limit(limit)
.skip(startindex)
.exec()
.then((docs) => {
const customerDataWithTimestamp = docs.map((doc, index) => ({
...doc._doc,
timestamp: timestamps[index],
}));
reply.send({
status_code: 200,
data: customerDataWithTimestamp,
count: docs.length,
});
})
.catch((err) => {
console.log(err);
reply.send({ error: err });
});
} catch (err) {
throw boom.boomify(err);
}
};
exports.getRejectCustomers = async (req, reply) => {
const limit = parseInt(req.query.limit) || 100;
const page = parseInt(req.query.page) || 1;
const startindex = (page - 1) * limit;
const supplierId = req.params.supplierId; // Assuming you have already authenticated the user and stored their ID in the request object
try {
const friendRequests = await FriendRequest.find({
supplierId,
status: ["rejected"],
});
console.log(friendRequests, supplierId, "su....");
const supplierIdsToInclude = friendRequests.map(
(request) => request.customerId
);
console.log(supplierIdsToInclude, "supplierIdsToInclude..");
await User.find({ customerId: { $in: supplierIdsToInclude } })
.limit(limit)
.skip(startindex)
.exec()
.then((docs) => {
reply.send({ status_code: 200, data: docs, count: docs.length });
})
.catch((err) => {
console.log(err);
reply.send({ error: err });
});
} catch (err) {
throw boom.boomify(err);
}
};
exports.getconnectedCustomers = async (req, reply) => {
const limit = parseInt(req.query.limit) || 100;
const page = parseInt(req.query.page) || 1;
const startindex = (page - 1) * limit;
const supplierId = req.params.supplierId; // Assuming you have already authenticated the user and stored their ID in the request object
try {
const friendRequests = await FriendRequest.find({
supplierId,
status: ["accepted"],
});
console.log(friendRequests, supplierId, "su....");
const supplierIdsToInclude = friendRequests.map(
(request) => request.customerId
);
console.log(supplierIdsToInclude, "supplierIdsToInclude..");
await User.find({ customerId: { $in: supplierIdsToInclude } })
.limit(limit)
.skip(startindex)
.exec()
.then((docs) => {
reply.send({ status_code: 200, data: docs, count: docs.length });
})
.catch((err) => {
console.log(err);
reply.send({ error: err });
});
} catch (err) {
throw boom.boomify(err);
}
};
// exports.uploadProfilePicture = async (req, reply) => {
// try {
// const supplierId = req.params.supplierId;
// const picture = req.body.picture;
// let profilePicture = await profilePictureSupplier.findOne({ supplierId });
// console.log(profilePicture,"profile===")
// if (!profilePicture) {
// profilePicture = new profilePictureSupplier({
// supplierId,
// picture,
// });
// } else {
// profilePicture.picture = picture;
// }
// await profilePicture.save();
// reply.send({ message: 'Profile picture uploaded successfully' });
// } catch (error) {
// reply.status(500).send({ error: error.message });
// }
// };
// const multer = require('multer');
// const fs = require('fs');
// // Multer storage configuration
// const storage = multer.diskStorage({
// destination: function (req, file, cb) {
// // Specify the destination folder for storing uploaded files
// cb(null, './uploads');
// },
// filename: function (req, file, cb) {
// // Generate a unique filename for the uploaded file
// cb(null, file.originalname);
// },
// });
// // Multer upload configuration
// const upload = multer({ storage: storage }).single('picture');
// // Handler for uploading profile picture
// exports.uploadProfilePicture = async (req, res) => {
// try {
// upload(req, res, async (err) => {
// if (err) {
// return res.status(400).send({ error: 'Failed to upload profile picture' });
// }
// const supplierId = req.params.supplierId;
// const picture = req.file.filename;
// let profilePicture = await ProfilePictureSupplier.findOne({ supplierId });
// if (!profilePicture) {
// profilePicture = new ProfilePictureSupplier({
// supplierId,
// picture,
// });
// } else {
// profilePicture.picture = picture;
// }
// await profilePicture.save();
// res.send({ message: 'Profile picture uploaded successfully' });
// });
// } catch (error) {
// res.status(500).send({ error: error.message });
// }
// };
// const { Storage } = require('@google-cloud/storage');
// const storage = new Storage({
// keyFilename :`/home/bhaskar/Downloads/arminta-tank-0f492875da39.json`,
// projectId : `arminta-tank`
// });
// const bucketName = 'armintaprofile_picture';
// exports.uploadProfilePicture = async (req, res) => {
// try {
// const supplierId = req.params.supplierId;
// const file = req.body.picture;
// // Check if the required properties are present
// if (!file) {
// return res.status(400).send({ error: 'No picture file provided' });
// }
// // Upload the file to the GCS bucket
// const bucket = storage.bucket(bucketName);
// const fileName = `${supplierId}/${file.originalname}`;
// const fileOptions = {
// metadata: {
// contentType: 'multipart/form-data',
// },
// };
// await bucket.upload(file.path, {
// destination: `armintaprofile_picture/${fileName}`,
// ...fileOptions,
// });
// const imageUrl = `https://storage.googleapis.com/${bucketName}/${fileName}`;
// console.log(imageUrl);
// let profilePicture = await ProfilePictureSupplier.findOne({ supplierId });
// console.log("profilePicture", profilePicture);
// if (!profilePicture) {
// profilePicture = new ProfilePictureSupplier({
// supplierId,
// picture: imageUrl,
// });
// } else {
// profilePicture.picture = imageUrl;
// }
// await profilePicture.save();
// // Delete the temporary file after uploading to GCS
// fs.unlinkSync(file.path);
// res.send({ message: 'Profile picture uploaded successfully' });
// } catch (error) {
// res.status(500).send({ error: error.message });
// }
// },
// const { Storage } = require('@google-cloud/storage');
// const storage = new Storage({
// keyFilename: '/home/bhaskar/Downloads/arminta-tank-0f492875da39.json',
// projectId: 'arminta-tank',
// });
// const bucketName = 'armintaprofile_picture';
// exports.uploadProfilePicture = async (req, res) => {
// try {
// const supplierId = req.params.supplierId;
// // Check if the required properties are present
// if (!req.files || !req.files.picture) {
// return res.status(400).send({ error: 'No picture file provided' });
// }
// const file = req.files.picture;
// console.log("file", file)
// // Upload the file to the GCS bucket
// const bucket = storage.bucket(bucketName);
// const fileName = `${supplierId}/${file.name}`;
// const fileOptions = {
// metadata: {
// contentType: file.mimetype,
// },
// };
// await bucket.upload(file.tempFilePath, {
// destination: fileName,
// ...fileOptions,
// });
// const imageUrl = `https://storage.googleapis.com/${bucketName}/${fileName}`;
// console.log(imageUrl);
// let profilePicture = await ProfilePictureSupplier.findOne({ supplierId });
// console.log('profilePicture', profilePicture);
// if (!profilePicture) {
// profilePicture = new ProfilePictureSupplier({
// supplierId,
// picture: imageUrl,
// });
// } else {
// profilePicture.picture = imageUrl;
// }
// await profilePicture.save();
// // Delete the temporary file after uploading to GCS
// fs.unlinkSync(file.tempFilePath);
// res.send({ message: 'Profile picture uploaded successfully' });
// } catch (error) {
// res.status(500).send({ error: error.message });
// }
// };
const { Storage } = require('@google-cloud/storage');
const fs = require('fs');
const storage = new Storage({
keyFilename: '/home/bhaskar/Downloads/arminta-tank-3c665db761bc.json',
projectId: 'arminta-tank',
});
const bucketName = 'armintaprofile_picture';
// exports.uploadProfilePicture = async (req, res) => {
// try {
// const supplierId = req.body.supplierId;
// // Check if the required properties are present
// if (!req.files || !req.files.picture) {
// return res.status(400).send({ error: 'No picture file provided' });
// }
// const file = `/home/bhaskar/Desktop/download.jpeg`;
// console.log("file", file)
// console.log("supplierId", supplierId)
// // Upload the file to the GCS bucket
// const bucket = storage.bucket(bucketName);
// const fileName = `${supplierId}/${file.name}`;
// const fileOptions = {
// metadata: {
// contentType: file.mimetype,
// },
// };
// await bucket.upload(file.tempFilePath, {
// destination: fileName,
// ...fileOptions,
// });
// const imageUrl = `https://storage.googleapis.com/${bucketName}/${fileName}`;
// let profilePicture = await profilePictureSupplier.findOne({ supplierId });
// if (!profilePicture) {
// profilePicture = new profilePictureSupplier({
// supplierId,
// picture: imageUrl,
// });
// } else {
// profilePicture.picture = imageUrl;
// }
// await profilePicture.save();
// // Delete the temporary file after uploading to GCS
// fs.unlinkSync(file.tempFilePath);
// res.send({ message: 'Profile picture uploaded successfully' });
// } catch (error) {
// res.status(500).send({ error: error.message });
// }
// };
// exports.uploadProfilePicture = async (req, res) => {
// try {
// upload(req, res, async (err) => {
// if (err) {
// return res.status(400).send({ error: 'Failed to upload profile picture' });
// }
// const supplierId = req.params.supplierId;
// const picture = req.file; // Assuming the file field in the request is named 'picture'
// // Upload the file to the GCS bucket
// const bucket = storage.bucket(bucketName);
// const fileName = `${supplierId}/${file.originalname}`;
// const fileOptions = {
// metadata: {
// contentType: file.mimetype,
// },
// };
// await bucket.upload(filepath, {
// destination: `armintaprofile_picture/${picture}`,
// ...fileOptions,
// });
// const imageUrl = `https://storage.googleapis.com/${bucketName}/${fileName}`;
// console.log(imageUrl)
// let profilePicture = await ProfilePictureSupplier.findOne({ supplierId });
// console.log("profilePicture", profilePicture)
// if (!profilePicture) {
// profilePicture = new ProfilePictureSupplier({
// supplierId,
// picture: imageUrl,
// });
// } else {
// profilePicture.picture = imageUrl;
// }
// await profilePicture.save();
// // Delete the temporary file after uploading to GCS
// fs.unlinkSync(file.path);
// res.send({ message: 'Profile picture uploaded successfully' });
// });
// } catch (error) {
// res.status(500).send({ error: error.message });
// }
// };
// exports.uploadProfilePicture = async (req, res) => {
// try {
// upload(req, res, async (err) => {
// if (err) {
// return res.status(400).send({ error: 'Failed to upload profile picture' });
// }
// const supplierId = req.params.supplierId;
// const picture = req.file.filename; // Assuming the file field in the request is named 'picture'
// // Upload the picture to the GCP bucket
// const bucketName = 'armintaprofile_picture';
// const bucket = storage.bucket(bucketName);
// const uploadPath = `armintaprofile_picture/${picture}`;
// await bucket.upload(req.file.path, {
// destination: uploadPath,
// });
// console.log("bucket",bucket)
// console.log(uploadPath, "uploadPath")
// // Get the public URL of the uploaded picture
// const file = bucket.file(uploadPath);
// const [metadata] = await file.getMetadata();
// const pictureUrl = metadata.mediaLink;
// let profilePicture = await profilePictureSupplier.findOne({ supplierId });
// if (!profilePicture) {
// profilePicture = new profilePictureSupplier({
// supplierId,
// picture: pictureUrl,
// });
// } else {
// profilePicture.picture = pictureUrl;
// }
// await profilePicture.save();
// res.send({ message: 'Profile picture uploaded successfully' });
// });
// } catch (error) {
// res.status(500).send({ error: error.message });
// }
// };
// Route for fetching profile picture data
fastify.get('/api/users/profile-picture-supplier/:supplierId', async (req, res) => {
try {
const supplierId = req.params.supplierId;
const profilePicture = await ProfilePictureSupplier.findOne({ supplierId });
if (!profilePicture) {
return res.status(404).send({ error: 'Profile picture not found' });
}
// Send the profile picture data as a response
res.send({ picture: profilePicture.picture });
} catch (error) {
res.status(500).send({ error: error.message });
}
});
exports.getSuppliersForPlanSearch = async (req, reply) => {
const { customerId } = req.params;
const {
type_of_water,
capacity: requestedCapacityStr,
quantity: requestedQuantityStr,
frequency, start_date, end_date, // currently not used to filter suppliers
// new filters
radius_from, radius_to,
rating_from, rating_to,
price_from, price_to,
pump
} = req.body;
// ---- helpers (kept inside as you prefer) ----
const parseFloatSafe = (v) => {
const n = parseFloat((v ?? "").toString().replace(/,/g, ""));
return Number.isFinite(n) ? n : NaN;
};
const parseIntSafe = (v) => {
const n = parseInt((v ?? "").toString().replace(/,/g, ""), 10);
return Number.isFinite(n) ? n : NaN;
};
const isValid = (n) => Number.isFinite(n);
const inRange = (n, from, to) =>
(!isValid(from) || n >= from) && (!isValid(to) || n <= to);
const normalizePump = (val) => {
if (val == null) return undefined;
const s = String(val).trim().toLowerCase();
if (["1","true","yes","y"].includes(s)) return true;
if (["0","false","no","n"].includes(s)) return false;
return undefined; // ignore if unknown
};
const parseLatLng = (raw) => {
// supports: "17.38,78.49" | {lat: 17.38, lng: 78.49} | [17.38, 78.49]
if (!raw) return null;
try {
if (typeof raw === "string") {
const parts = raw.split(",").map(x => parseFloat(x.trim()));
if (parts.length === 2 && parts.every(Number.isFinite)) return { lat: parts[0], lng: parts[1] };
// try JSON
const j = JSON.parse(raw);
return parseLatLng(j);
}
if (Array.isArray(raw) && raw.length === 2) {
const [lat, lng] = raw.map(Number);
if (Number.isFinite(lat) && Number.isFinite(lng)) return { lat, lng };
}
if (typeof raw === "object" && raw !== null) {
const lat = parseFloat(raw.lat ?? raw.latitude);
const lng = parseFloat(raw.lng ?? raw.lon ?? raw.longitude);
if (Number.isFinite(lat) && Number.isFinite(lng)) return { lat, lng };
}
} catch (_) {}
return null;
};
const haversineKm = (a, b) => {
const R = 6371;
const dLat = (b.lat - a.lat) * Math.PI / 180;
const dLng = (b.lng - a.lng) * Math.PI / 180;
const s1 = Math.sin(dLat/2) ** 2;
const s2 = Math.cos(a.lat*Math.PI/180) * Math.cos(b.lat*Math.PI/180) * Math.sin(dLng/2) ** 2;
return 2 * R * Math.asin(Math.sqrt(s1 + s2));
};
const getSupplierRating = (s) => {
// adapt to whatever field you actually store
const cands = [s.rating, s.avgRating, s.averageRating, s.overallRating];
const n = cands.find(x => Number.isFinite(Number(x)));
return Number(n ?? NaN);
};
// ---- end helpers ----
// parse inputs
const requestedCapacity = parseFloatSafe(requestedCapacityStr) || 0;
const requestedQuantity = parseIntSafe(requestedQuantityStr) || 0;
const totalRequiredCapacity = requestedCapacity * requestedQuantity;
const priceFrom = parseIntSafe(price_from);
const priceTo = parseIntSafe(price_to);
const ratingFrom = parseFloatSafe(rating_from);
const ratingTo = parseFloatSafe(rating_to);
const radiusFrom = parseFloatSafe(radius_from);
const radiusTo = parseFloatSafe(radius_to);
const pumpWanted = normalizePump(pump);
try {
// favorites + customer coords (for radius)
const customer = await User.findOne({ customerId }, { favorate_suppliers: 1, googleLocation: 1, location: 1 }).lean();
const favoriteSet = new Set(customer?.favorate_suppliers || []);
const customerCoords =
parseLatLng(customer?.googleLocation) ||
parseLatLng(customer?.location);
// 1) Tankers base query: by type_of_water (+ pump if requested)
const tankerQuery = {};
if (type_of_water?.trim()) tankerQuery.typeofwater = type_of_water.trim();
if (pumpWanted !== undefined) {
// try to match common representations
tankerQuery.$or = [
{ pump: pumpWanted ? { $in: [true, "1", "yes", "true", 1, "Y", "y"] } : { $in: [false, "0", "no", "false", 0, "N", "n"] } },
{ pumpAvailable: pumpWanted } // if you store as boolean
];
}
let tankers = await Tanker.find(tankerQuery).lean();
// 2) Price range on tanker.price
if (isValid(priceFrom) || isValid(priceTo)) {
tankers = tankers.filter(t => {
const p = parseIntSafe(t.price);
return isValid(p) && inRange(p, priceFrom, priceTo);
});
}
// 3) Group by supplier
const supplierTankerMap = {};
for (const t of tankers) {
if (!t?.supplierId) continue;
(supplierTankerMap[t.supplierId] ||= []).push(t);
}
// 4) Capacity qualification
let qualified = [];
for (const [supplierId, supplierTankers] of Object.entries(supplierTankerMap)) {
const totalAvail = supplierTankers.reduce((sum, tt) => sum + (parseFloatSafe(tt.capacity) || 0), 0);
if (requestedCapacity > 0 && requestedQuantity > 0 && totalAvail < totalRequiredCapacity) continue;
qualified.push({ supplierId, tankers: supplierTankers });
}
// 5) Fetch suppliers for remaining filters (rating & radius) + flags
const supplierIds = qualified.map(q => q.supplierId);
const [suppliersData, acceptedReqs] = await Promise.all([
Supplier.find({ supplierId: { $in: supplierIds } }).lean(),
FriendRequest.find(
{ customerId, supplierId: { $in: supplierIds }, status: "accepted" },
{ supplierId: 1, _id: 0 }
).lean()
]);
// Build quick lookup
const supplierById = new Map(suppliersData.map(s => [s.supplierId, s]));
const connectedSet = new Set(acceptedReqs.map(r => r.supplierId));
// 6) Apply rating & radius filters on suppliers
if (isValid(ratingFrom) || isValid(ratingTo) || (isValid(radiusFrom) || isValid(radiusTo))) {
qualified = qualified.filter(q => {
const s = supplierById.get(q.supplierId);
if (!s) return false;
// rating
if (isValid(ratingFrom) || isValid(ratingTo)) {
const r = getSupplierRating(s);
if (!isValid(r) || !inRange(r, ratingFrom, ratingTo)) return false;
}
// radius (requires coords on both sides)
if ((isValid(radiusFrom) || isValid(radiusTo)) && customerCoords) {
const supCoords =
parseLatLng(s.googleLocation) ||
parseLatLng(s.location) ||
parseLatLng(s.addressLocation);
if (!supCoords) return false;
const distKm = haversineKm(customerCoords, supCoords);
if (!inRange(distKm, radiusFrom, radiusTo)) return false;
}
return true;
});
}
// 7) Build response with flags + optional 'requestedBooking' flag
const suppliers = [];
for (const q of qualified) {
const s = supplierById.get(q.supplierId);
if (!s) continue;
const isConnected = connectedSet.has(q.supplierId);
const isFavorite = favoriteSet.has(q.supplierId);
// If you want to expose a hint that user has already sent a single-day request earlier
const requestedBookingRecord = await RequestedBooking.findOne({
customerId,
"requested_suppliers.supplierId": q.supplierId
}, { time: 1 }).lean();
suppliers.push({
supplier: s,
tankers: q.tankers,
isConnected,
isFavorite,
requestedBooking: requestedBookingRecord ? { status: true, time: requestedBookingRecord.time } : { status: false }
});
}
return reply.send({ status_code: 200, suppliers });
} catch (err) {
console.error(err);
return reply.send({
status_code: 500,
message: "Something went wrong",
error: err.message
});
}
};
// controllers/validationHandler.js (add below the previous handler)
// exports.createRequestedPlanBooking = async (req, reply) => {
// const {
// customerId,
// type_of_water,
// capacity,
// quantity,
// start_date,
// end_date,
// time,
// frequency, // "daily" | "weekly_once" | "weekly_twice" | "weekly_thrice" | "weekly"
// weekly_count, // used only if frequency === "weekly"
// requested_suppliers
// } = req.body;
// // helpers inside function (as you prefer)
// const parseCapacity = (v) => parseFloat((v || "0").toString().replace(/,/g, "")) || 0;
// const parseIntSafe = (v) => parseInt((v || "0").toString().replace(/,/g, ""), 10) || 0;
// const toISODate = (d) => d.toISOString().slice(0, 10);
// const mkUTCDate = (yyyy_mm_dd) => {
// const [y, m, d] = (yyyy_mm_dd || "").split("-").map(Number);
// return new Date(Date.UTC(y, (m || 1) - 1, d || 1));
// };
// const normalizeWeeklyCount = (freq, wc) => {
// if (freq === "weekly_once") return 1;
// if (freq === "weekly_twice") return 2;
// if (freq === "weekly_thrice") return 3;
// if (freq === "weekly") return wc || 1;
// return 1;
// };
// const computeWeeklyDOWs = ({ anchorDow, weeklyCount }) => {
// if (weeklyCount === 1) return [anchorDow];
// if (weeklyCount === 2) return [anchorDow, (anchorDow + 3) % 7];
// if (weeklyCount === 3) return [anchorDow, (anchorDow + 2) % 7, (anchorDow + 4) % 7];
// return [anchorDow];
// };
// const generateDates = ({ frequency, start_date, end_date, weekly_count }) => {
// const start = mkUTCDate(start_date);
// const end = mkUTCDate(end_date);
// if (isNaN(start) || isNaN(end)) throw new Error("Invalid start_date or end_date");
// if (end < start) throw new Error("end_date must be after or equal to start_date");
// // ~3 months cap
// const maxMs = 92 * 24 * 60 * 60 * 1000;
// if ((end - start) > maxMs) throw new Error("Range exceeds 3 months");
// const out = [];
// if (frequency === "daily") {
// for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {
// out.push(toISODate(d));
// }
// return out;
// }
// if (frequency.startsWith("weekly") || frequency === "weekly") {
// const wc = normalizeWeeklyCount(frequency, weekly_count);
// const dows = computeWeeklyDOWs({ anchorDow: start.getUTCDay(), weeklyCount: wc });
// const set = new Set(dows);
// for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {
// if (set.has(d.getUTCDay())) out.push(toISODate(d));
// }
// return out;
// }
// throw new Error("Unsupported frequency");
// };
// try {
// if (!customerId || !type_of_water || !capacity || !quantity ||
// !start_date || !end_date || !time || !frequency || !requested_suppliers) {
// return reply.code(400).send({
// status_code: 400,
// message: "Missing required fields"
// });
// }
// const cap = parseCapacity(capacity);
// const qty = parseIntSafe(quantity);
// const total_required_capacity = cap * qty;
// const dates = generateDates({ frequency, start_date, end_date, weekly_count });
// if (dates.length === 0) {
// return reply.code(400).send({ status_code: 400, message: "No dates generated for given inputs" });
// }
// const doc = new RecurringRequestedBooking({
// customerId,
// type_of_water,
// capacity,
// quantity,
// total_required_capacity,
// frequency,
// weekly_count: normalizeWeeklyCount(frequency, weekly_count),
// start_date,
// end_date,
// time,
// dates,
// requested_suppliers,
// status: "pending"
// });
// await doc.save();
// return reply.send({
// status_code: 200,
// message: "Plan requested booking created successfully",
// count: dates.length,
// dates,
// data: doc
// });
// } catch (err) {
// console.error(err);
// return reply.code(500).send({
// status_code: 500,
// message: "Something went wrong while saving",
// error: err.message
// });
// }
// };
// controllers/plan.controller.js
//const RecurringRequestedBooking = require("../models/RecurringRequestedBooking");
// ---------- Helpers ----------
const MONTHS = {
jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5,
jul: 6, aug: 7, sep: 8, oct: 9, nov: 10, dec: 11,
};
const parseCapacity = (v) => parseFloat((v ?? "0").toString().replace(/,/g, "")) || 0;
const parseIntSafe = (v) => parseInt((v ?? "0").toString().replace(/,/g, ""), 10) || 0;
const toISODate = (d) => d.toISOString().slice(0, 10);
/**
* Accepts:
* - "YYYY-MM-DD"
* - "DD-MMM-YYYY"
* - "DD-MMM-YYYY - HH:mm" (time portion ignored for date gen)
* Returns a Date in UTC midnight of that calendar day.
*/
const mkUTCDate = (input) => {
if (!input || typeof input !== "string") throw new Error("Invalid date string");
const s = input.trim();
// ISO: YYYY-MM-DD (optionally with time, but we only take the first three parts)
const iso = s.match(/^(\d{4})-(\d{2})-(\d{2})/);
if (iso) {
const y = Number(iso[1]);
const m = Number(iso[2]) - 1;
const d = Number(iso[3]);
return new Date(Date.UTC(y, m, d));
}
// D-MMM-YYYY (optional " - HH:mm")
const mmm = s.match(/^(\d{1,2})-([A-Za-z]{3})-(\d{4})(?:\s*-\s*(\d{1,2}):(\d{2}))?$/);
if (mmm) {
const d = Number(mmm[1]);
const mon = MONTHS[mmm[2].toLowerCase()];
const y = Number(mmm[3]);
if (mon == null) throw new Error("Invalid month abbreviation in date");
return new Date(Date.UTC(y, mon, d));
}
throw new Error("Unsupported date format. Use YYYY-MM-DD or DD-MMM-YYYY (- HH:mm).");
};
const normalizeWeeklyCount = (freq, wc) => {
if (freq === "weekly_once") return 1;
if (freq === "weekly_twice") return 2;
if (freq === "weekly_thrice") return 3;
if (freq === "weekly") return wc || 1;
return 1;
};
const computeWeeklyDOWs = ({ anchorDow, weeklyCount }) => {
if (weeklyCount === 1) return [anchorDow];
if (weeklyCount === 2) return [anchorDow, (anchorDow + 3) % 7];
if (weeklyCount === 3) return [anchorDow, (anchorDow + 2) % 7, (anchorDow + 4) % 7];
return [anchorDow];
};
const generateDates = ({ frequency, start_date, end_date, weekly_count }) => {
const start = mkUTCDate(start_date);
const end = mkUTCDate(end_date);
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
throw new Error("Invalid start_date or end_date");
}
if (end < start) throw new Error("end_date must be after or equal to start_date");
// ~3 months cap
const maxMs = 92 * 24 * 60 * 60 * 1000;
if ((end - start) > maxMs) throw new Error("Range exceeds 3 months");
const out = [];
if (frequency === "daily") {
for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {
out.push(toISODate(d));
}
return out;
}
if (frequency.startsWith("weekly") || frequency === "weekly") {
const wc = normalizeWeeklyCount(frequency, weekly_count);
const dows = computeWeeklyDOWs({ anchorDow: start.getUTCDay(), weeklyCount: wc });
const set = new Set(dows);
for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {
if (set.has(d.getUTCDay())) out.push(toISODate(d));
}
return out;
}
throw new Error("Unsupported frequency");
};
const ensureRequestedSuppliers = (arr) => {
const inArr = Array.isArray(arr) ? arr : [];
return inArr.map((x) => ({
supplierId: x?.supplierId ?? "",
quoted_amount: typeof x?.quoted_amount === "number" ? x.quoted_amount : 0,
time: x?.time ?? null,
status: x?.status ?? "pending",
}));
};
// ---------- Controller ----------
exports.createRequestedPlanBooking = async (req, reply) => {
try {
const {
customerId,
type_of_water,
capacity,
quantity,
start_date,
end_date,
time,
frequency, // "daily" | "weekly_once" | "weekly_twice" | "weekly_thrice" | "weekly"
weekly_count, // used only if frequency === "weekly"
requested_suppliers
} = req.body || {};
// Basic presence check
const missing = [
["customerId", customerId],
["type_of_water", type_of_water],
["capacity", capacity],
["quantity", quantity],
["start_date", start_date],
["end_date", end_date],
["time", time],
["frequency", frequency],
["requested_suppliers", requested_suppliers],
].filter(([k, v]) => v == null || (typeof v === "string" && v.trim() === ""));
if (missing.length) {
return reply.code(400).send({
status_code: 400,
message: `Missing required fields: ${missing.map(([k]) => k).join(", ")}`
});
}
// Validate frequency early
const ALLOWED_FREQ = new Set(["daily", "weekly_once", "weekly_twice", "weekly_thrice", "weekly"]);
if (!ALLOWED_FREQ.has(frequency)) {
return reply.code(400).send({
status_code: 400,
message: "Invalid frequency. Allowed: daily, weekly_once, weekly_twice, weekly_thrice, weekly"
});
}
// Parse numbers
const cap = parseCapacity(capacity);
const qty = parseIntSafe(quantity);
const total_required_capacity = cap * qty;
if (cap <= 0 || qty <= 0) {
return reply.code(400).send({
status_code: 400,
message: "capacity and quantity must be positive numbers"
});
}
// Build dates
let dates;
try {
dates = generateDates({ frequency, start_date, end_date, weekly_count });
} catch (e) {
return reply.code(400).send({
status_code: 400,
message: e.message || "Invalid dates"
});
}
if (!Array.isArray(dates) || dates.length === 0) {
return reply.code(400).send({
status_code: 400,
message: "No dates generated for the given inputs"
});
}
// Suppliers normalization
const suppliers = ensureRequestedSuppliers(requested_suppliers);
if (suppliers.length === 0) {
return reply.code(400).send({
status_code: 400,
message: "requested_suppliers must contain at least one supplier"
});
}
const doc = new RecurringRequestedBooking({
customerId,
type_of_water,
capacity,
quantity,
total_required_capacity,
frequency,
weekly_count: normalizeWeeklyCount(frequency, weekly_count),
start_date,
end_date,
time,
dates,
requested_suppliers: suppliers,
status: "pending"
});
await doc.save();
return reply.send({
status_code: 200,
message: "Plan requested booking created successfully",
count: dates.length,
dates,
data: doc
});
} catch (err) {
console.error(err);
return reply.code(500).send({
status_code: 500,
message: "Something went wrong while saving",
error: err.message
});
}
};