changes in plans

master^2
Varun 1 month ago
parent 188ff245fa
commit d2540c55ee

@ -2135,45 +2135,193 @@ exports.getSuppliersForPlanSearch = async (req, reply) => {
// 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;
// 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;
// }
// 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 (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 }) => {
};
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 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 (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
@ -2181,6 +2329,7 @@ exports.createRequestedPlanBooking = async (req, reply) => {
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));
@ -2199,24 +2348,100 @@ exports.createRequestedPlanBooking = async (req, reply) => {
}
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 {
if (!customerId || !type_of_water || !capacity || !quantity ||
!start_date || !end_date || !time || !frequency || !requested_suppliers) {
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"
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;
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" });
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({
@ -2231,7 +2456,7 @@ exports.createRequestedPlanBooking = async (req, reply) => {
end_date,
time,
dates,
requested_suppliers,
requested_suppliers: suppliers,
status: "pending"
});
@ -2254,3 +2479,4 @@ exports.createRequestedPlanBooking = async (req, reply) => {
}
};

@ -181,30 +181,62 @@ const requestedBookingSchema = new mongoose.Schema({
// 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 requestedSupplier1Schema = new mongoose.Schema({
supplierId: String,
quoted_amount: Number,
time: { type: String, default: null },
status: { type: String, default: "pending" },
supplierId: { type: String, required: true },
quoted_amount: { type: Number, default: 0 },
time: { type: String, default: null }, // keep as string to match current payloads
status: { type: String, enum: ["pending", "accepted", "rejected"], 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 },
type_of_water: { type: String, required: true },
capacity: { type: String, required: true }, // keep as sent by UI, we also store parsed number below if you want
quantity: { type: String, required: true },
total_required_capacity: { type: Number, required: true }, // capacity * quantity (numeric)
frequency: {
type: String,
enum: ["daily", "weekly_once", "weekly_twice", "weekly_thrice", "weekly"],
required: true
},
weekly_count: { type: Number, default: 1 },
start_date: { type: String, required: true }, // storing original string for audit
end_date: { type: String, required: true },
time: String,
dates: [String],
requested_suppliers: [requestedSupplier1Schema],
status: { type: String, default: "pending" },
}, { timestamps: true });
time: { type: String, required: true },
dates: { type: [String], default: [] }, // ISO "YYYY-MM-DD" strings
requested_suppliers: { type: [requestedSupplier1Schema], default: [] },
status: { type: String, default: "pending" },
}, { timestamps: true });
const RequestedBooking = mongoose.model('RequestedBooking', requestedBookingSchema);

Loading…
Cancel
Save