plans apis for book a tanker

master^2
Varun 1 month ago
parent 6cb30b7dfe
commit 3f347b4f32

@ -1,6 +1,6 @@
//Get the data models //Get the data models
const { Supplier, DeliveryBoy, profilePictureSupplier } = require("../models/supplier"); const { Supplier, DeliveryBoy, profilePictureSupplier } = require("../models/supplier");
const { FriendRequest,RequestedBooking } = require("../models/supplier"); const { FriendRequest,RequestedBooking,RecurringRequestedBooking } = require("../models/supplier");
const { Tanker,Tankerbooking } = require("../models/tankers"); const { Tanker,Tankerbooking } = require("../models/tankers");
const { ProfilePicture, User } = require("../models/User"); const { ProfilePicture, User } = require("../models/User");
const supplierController = require("../controllers/supplierController"); const supplierController = require("../controllers/supplierController");
@ -1920,3 +1920,221 @@ fastify.get('/api/users/profile-picture-supplier/:supplierId', async (req, res)
res.status(500).send({ error: error.message }); 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 are provided by UI but not used for filtering now
} = req.body;
// helpers inside function (per your preference)
const parseCapacity = (v) => parseFloat((v || "0").toString().replace(/,/g, "")) || 0;
const requestedCapacity = parseCapacity(requestedCapacityStr);
const requestedQuantity = parseInt((requestedQuantityStr || "0").toString(), 10) || 0;
const totalRequiredCapacity = requestedCapacity * requestedQuantity;
try {
// favorites
const customer = await User.findOne({ customerId }, { favorate_suppliers: 1 }).lean();
const favoriteSet = new Set(customer?.favorate_suppliers || []);
// Tanker filter: ONLY by type_of_water (NO booked tanker exclusion, NO price/radius/rating)
const tankerQuery = {};
if (type_of_water && type_of_water.trim() !== "") {
tankerQuery.typeofwater = type_of_water;
}
const tankers = await Tanker.find(tankerQuery).lean();
// Group tankers by supplier
const supplierTankerMap = {};
for (const t of tankers) {
if (!supplierTankerMap[t.supplierId]) supplierTankerMap[t.supplierId] = [];
supplierTankerMap[t.supplierId].push(t);
}
// Capacity check per supplier (capacity * quantity)
const qualified = [];
for (const [supplierId, supplierTankers] of Object.entries(supplierTankerMap)) {
const totalAvail = supplierTankers.reduce((sum, tt) => sum + parseCapacity(tt.capacity), 0);
if (requestedCapacity > 0 && requestedQuantity > 0) {
if (totalAvail < totalRequiredCapacity) continue;
}
qualified.push({ supplierId, tankers: supplierTankers });
}
// Fetch suppliers + connection 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()
]);
const supplierById = new Map(suppliersData.map(s => [s.supplierId, s]));
const connectedSet = new Set(acceptedReqs.map(r => r.supplierId));
// Optional: check if any (single-day) requested booking exists with that supplier
const suppliers = [];
for (const q of qualified) {
const supplierData = supplierById.get(q.supplierId);
const friendRequestAccepted = connectedSet.has(q.supplierId);
const isFavorite = favoriteSet.has(q.supplierId);
const requestedBookingRecord = await RequestedBooking.findOne({
customerId,
"requested_suppliers.supplierId": q.supplierId
}, { time: 1 }).lean();
const requestedBooking = requestedBookingRecord
? { status: true, time: requestedBookingRecord.time }
: { status: false };
suppliers.push({
supplier: supplierData,
tankers: q.tankers,
isConnected: friendRequestAccepted,
isFavorite,
requestedBooking
});
}
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
});
}
};

@ -179,8 +179,36 @@ const requestedBookingSchema = new mongoose.Schema({
status: { type: String, default: "pending" }, status: { type: String, default: "pending" },
}, { timestamps: true }); }, { timestamps: true });
// models/RecurringRequestedBooking.js
const requestedSupplier1Schema = new mongoose.Schema({
supplierId: String,
quoted_amount: Number,
time: { type: String, default: null },
status: { type: String, default: "pending" },
}, { _id: false });
const recurringRequestedBookingSchema = new mongoose.Schema({
customerId: { type: String, required: true },
type_of_water: String,
capacity: String,
quantity: String,
total_required_capacity: Number,
frequency: { type: String, enum: ["daily","weekly_once","weekly_twice","weekly_thrice","weekly"], required: true },
weekly_count: { type: Number, enum: [1,2,3] },
start_date: { type: String, required: true },
end_date: { type: String, required: true },
time: String,
dates: [String],
requested_suppliers: [requestedSupplier1Schema],
status: { type: String, default: "pending" },
}, { timestamps: true });
const RequestedBooking = mongoose.model('RequestedBooking', requestedBookingSchema); const RequestedBooking = mongoose.model('RequestedBooking', requestedBookingSchema);
const RecurringRequestedBooking = mongoose.model("RecurringRequestedBooking", recurringRequestedBookingSchema);
const Supplier = mongoose.model("Supplier", supplierSchema); const Supplier = mongoose.model("Supplier", supplierSchema);
//const DeliveryAgent = mongoose.model("DeliveryAgent", deliveryAgent); //const DeliveryAgent = mongoose.model("DeliveryAgent", deliveryAgent);
@ -188,6 +216,6 @@ const FriendRequest = mongoose.model('FriendRequest', friendRequestSchema);
const DeliveryBoy = mongoose.model('DeliveryBoy', deliveryBoySchema); const DeliveryBoy = mongoose.model('DeliveryBoy', deliveryBoySchema);
const profilePictureSupplier = mongoose.model('ProfilePictureSupplier', profilePictureSupplierSchema); const profilePictureSupplier = mongoose.model('ProfilePictureSupplier', profilePictureSupplierSchema);
module.exports = { Supplier, generateSupplierId, FriendRequest,DeliveryBoy, profilePictureSupplier,RequestedBooking} module.exports = { Supplier, generateSupplierId, FriendRequest,DeliveryBoy, profilePictureSupplier,RequestedBooking,RecurringRequestedBooking}

@ -160,6 +160,82 @@ fastify.post("/api/requestedbookings", {
handler: validationHandler.getPendingSuppliers, handler: validationHandler.getPendingSuppliers,
}); });
fastify.post("/api/plan/suppliers/:customerId", {
schema: {
tags: ["Supplier-Data"],
summary: "Search suppliers for Plans page",
description: "Filters by type_of_water and capacity×quantity. No bookings/price/radius/rating filters.",
params: {
type: "object",
required: ["customerId"],
properties: { customerId: { type: "string" } },
},
body: {
type: "object",
required: ["type_of_water", "capacity", "quantity", "frequency", "start_date", "end_date"],
properties: {
type_of_water: { type: "string" },
capacity: { type: "string" }, // UI field
quantity: { type: "string" }, // UI field
frequency: { // UI field: daily/weekly_once/_twice/_thrice
type: "string",
enum: ["daily","weekly_once","weekly_twice","weekly_thrice","weekly"]
},
start_date: { type: "string" }, // UI field "Start date"
end_date: { type: "string" } // UI field "End date"
},
additionalProperties: false
},
security: [{ basicAuth: [] }],
},
handler: validationHandler.getSuppliersForPlanSearch,
});
fastify.post("/api/requestedplanbookings", {
schema: {
tags: ["Supplier-Data"],
summary: "Create plan requested booking (daily/weekly once|twice|thrice)",
body: {
type: "object",
required: [
"customerId","type_of_water","capacity","quantity",
"start_date","end_date","time","frequency","requested_suppliers"
],
properties: {
customerId: { type: "string" },
type_of_water: { type: "string" },
capacity: { type: "string" },
quantity: { type: "string" },
start_date: { type: "string" }, // "YYYY-MM-DD"
end_date: { type: "string" }, // "YYYY-MM-DD"
time: { type: "string" }, // "HH:mm"
frequency: {
type: "string",
enum: ["daily","weekly_once","weekly_twice","weekly_thrice","weekly"]
},
weekly_count: { type: "integer", minimum: 1, maximum: 3 }, // only if frequency === "weekly"
requested_suppliers: {
type: "array",
minItems: 1,
items: {
type: "object",
required: ["supplierId","quoted_amount"],
properties: {
supplierId: { type: "string" },
quoted_amount: { type: "number" },
time: { type: "string" }
},
additionalProperties: false
}
}
},
additionalProperties: false
},
security: [{ basicAuth: [] }]
},
handler: validationHandler.createRequestedPlanBooking
});
fastify.get("/api/rejectSuppliers/:customerId", { fastify.get("/api/rejectSuppliers/:customerId", {
schema: { schema: {
tags: ["Supplier-Data"], tags: ["Supplier-Data"],

Loading…
Cancel
Save