|
|
|
//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
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|