accept plans for supplier

master^2
Varun 3 weeks ago
parent 22f70b9b54
commit 1880763a8a

@ -10,7 +10,7 @@ const saltRounds = 10;
//Get the data models
const { RequestedBooking,Supplier , generateSupplierId, DeliveryBoy} = require('../models/supplier');
const { RecurringRequestedBooking,RequestedBooking,Supplier , generateSupplierId, DeliveryBoy} = require('../models/supplier');
const { Tankerbooking} = require("../models/tankers")
@ -299,3 +299,234 @@ exports.respondToRequestedBooking = async (req, reply) => {
};
// controllers/supplier.controller.js
// const boom = require("@hapi/boom");
// const mongoose = require("mongoose");
// // MODELS (adjust paths/names to your project)
// const RecurringRequestedBooking = require("../models/recurringRequestedBooking.model");
// const TankerBooking = require("../models/tankerBooking.model");
// // Common party models you likely have in your DB:
// const Customer = require("../models/customer.model"); // e.g., { customerId, name, phone, address, latitude, longitude }
// const Supplier = require("../models/supplier.model"); // e.g., { supplierId, name, phone, tankerName, address, latitude, longitude }
const parseNumber = (v, def = 0) => {
if (v === null || v === undefined) return def;
const n = parseFloat(String(v).replace(/,/g, ""));
return Number.isFinite(n) ? n : def;
};
const mkBookingId = (prefix = "RBK") => {
const ts = new Date().toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
const rnd = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
return `${prefix}-${ts}-${rnd}`;
};
const isIsoYMD = (s) => /^\d{4}-\d{2}-\d{2}$/.test(s);
// "2025-10-21" -> "21-Oct-2025" (to match your old saved sample)
const formatDDMonYYYY = (isoYmd) => {
if (!isIsoYMD(isoYmd)) return isoYmd;
const [y, m, d] = isoYmd.split("-").map(Number);
const mon = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][(m || 1) - 1];
return `${String(d).padStart(2,"0")}-${mon}-${y}`;
};
exports.respondToRecurringRequestedBooking = async (req, reply) => {
const { _id } = req.params;
const { action, supplierId } = req.body;
if (!mongoose.Types.ObjectId.isValid(_id)) {
return reply.code(400).send({ message: "Invalid recurring requested booking ID" });
}
if (!["accept", "reject"].includes(action)) {
return reply.code(400).send({ message: "Action must be 'accept' or 'reject'" });
}
try {
const booking = await RecurringRequestedBooking.findById(_id);
if (!booking) {
return reply.code(404).send({ message: "Recurring requested booking not found" });
}
const supplierEntry = booking.requested_suppliers.find((s) => s.supplierId === supplierId);
if (!supplierEntry) {
return reply.code(404).send({ message: "Supplier not found in this booking" });
}
// Update supplier response on the recurring request
supplierEntry.status = action === "accept" ? "accepted" : "rejected";
await booking.save();
if (action === "reject") {
return reply.code(200).send({
status_code: 200,
message: "Recurring booking rejected by supplier successfully",
data: booking,
});
}
// ACCEPT: build per-date TankerBooking docs with rich fields
const allDates = Array.isArray(booking.dates) ? booking.dates.filter(isIsoYMD) : [];
if (!allDates.length) {
return reply.code(400).send({ message: "No valid ISO dates found in booking.dates" });
}
// Preload related party info to fill address/phones/names
const [customerDoc, supplierDoc] = await Promise.all([
User.findOne({ customerId: booking.customerId }).lean(),
Supplier.findOne({ supplierId: supplierId }).lean(),
]);
// Pull commonly needed values (tolerant defaults to match legacy)
const customerPhone = customerDoc?.phone ?? null;
const supplierPhone = supplierDoc?.phone ?? null;
const customerName = customerDoc?.username ?? customerDoc?.displayName ?? "";
const supplierName = supplierDoc?.suppliername ?? supplierDoc?.companyName ?? "";
const tankerName = supplierDoc?.tankerName ?? null;
const tankName = null; // if you associate a tank per-customer, populate from your Tank model here
const tankLocation = null; // same as above
// prefer customer address (your legacy sample stores a geocoded customer address)
const address = customerDoc?.profile.address1 ?? null;
const latitude = customerDoc?.latitude ?? null;
const longitude = customerDoc?.longitude ?? null;
// price: from suppliers quoted_amount in this request (fallback null)
const price = (supplierEntry?.quoted_amount ?? null) !== null
? String(supplierEntry.quoted_amount)
: null;
// numeric fields
const numericCapacity = parseNumber(booking.capacity);
const numericQuantity = parseNumber(booking.quantity);
const totalRequired = Number.isFinite(booking.total_required_capacity)
? booking.total_required_capacity
: numericCapacity * numericQuantity;
// dedupe check
const existing = await Tankerbooking.find(
{
customerId: booking.customerId,
supplierId: supplierId,
date: { $in: allDates },
time: booking.time, // keep your stored time format intact
},
{ date: 1 }
).lean();
const existingSet = new Set((existing || []).map(e => e.date));
const newDates = allDates.filter(d => !existingSet.has(d));
if (!newDates.length) {
return reply.code(200).send({
status_code: 200,
message: "All dates already have bookings; nothing to create.",
data: { created: 0, skippedExistingDates: allDates },
});
}
// ---------- BUILD ENRICHED DOCS (matches your legacy example fields) ----------
const todayIso = new Date().toISOString().slice(0, 10);
const docs = newDates.map((d) => ({
// Required/IDs
customerId: booking.customerId,
supplierId: supplierId,
bookingid: mkBookingId("RBK"),
// Legacy display & logistics
tankName, // null (fill if you link tank per-customer)
tankLocation, // null (fill if available)
tankerName, // from Supplier if present
// Dates/times (kept both ISO & legacy formats as you showed)
dateOfOrder: todayIso, // "2025-09-10"
expectedDateOfDelivery: formatDDMonYYYY(d), // "21-Oct-2025" style (legacy sample)
date: d, // keep ISO in `date` too
time: booking.time, // keep your request time as-is
// Water & capacity
type_of_water: booking.type_of_water,
typeofwater: booking.type_of_water, // legacy field name kept too
capacity: booking.capacity, // e.g., "100" or "10,000 L"
quantity: booking.quantity, // string
total_required_capacity: totalRequired,
// Money / status
price: price, // from quoted_amount (string) or null
payment_status: "due",
orderStatus: "accepted",
// Contacts & names
address: address, // from customer
customerPhone: customerPhone,
supplierPhone: supplierPhone,
customerName: customerName,
supplierName: supplierName,
// Delivery defaults (match your legacy doc)
delivery_agent: "null",
delivery_agent_mobile: "null",
delivery_agent_alternative_mobile: "null",
// Metering defaults
initial_water_level: "null",
final_water_level: "null",
start_time: "null",
stop_time: "null",
quantityDelivered: null,
// Accounting defaults
amount_paid: null,
amount_due: null,
distrubance_price: "none",
amount_difference: "none",
payment_mode: null,
remarks: null,
// Device/geo defaults
tankerRunningStatus: "0",
latitude: latitude ?? undefined, // keep same field names as your legacy doc
longitude: longitude ?? undefined, // if not available, omit field
// Misc you already store
frequency: booking.frequency,
weekly_count: booking.weekly_count ?? 1,
deliveredDate: null,
distrubance_status: "0",
}));
// ---------------------------------------------------------------------------
// Insert without transactions, tolerate duplicates if unique index exists
let insertedCount = 0;
let duplicateErrors = 0;
try {
const res = await Tankerbooking.collection.insertMany(docs, { ordered: false });
insertedCount = res.insertedCount || 0;
} catch (e) {
if (e && e.writeErrors && Array.isArray(e.writeErrors)) {
insertedCount = e.result?.nInserted ?? 0;
duplicateErrors = e.writeErrors.length;
} else {
throw e;
}
}
return reply.code(200).send({
status_code: 200,
message: `Recurring booking accepted. Created ${insertedCount} tanker booking(s).`,
data: {
createdDates: newDates.slice(0, insertedCount),
skippedExistingDates: allDates.filter(d => existingSet.has(d)),
duplicateConflicts: duplicateErrors,
},
});
} catch (err) {
console.error(err);
throw boom.internal("Failed to update recurring supplier response", err);
}
};

@ -746,7 +746,38 @@ fastify.route({
handler: supplierController.respondToRequestedBooking
});
fastify.route({
method: "POST",
url: "/api/supplier/recurring/respond/:_id",
schema: {
description:
"Supplier accepts or rejects a recurring requested booking; on accept, creates bookings for each date in the stored 'dates' array.",
tags: ["Supplier-Data"],
summary: "Supplier action on recurring requested booking",
params: {
type: "object",
properties: {
_id: { type: "string", description: "Recurring Requested Booking ID" },
},
required: ["_id"],
},
body: {
type: "object",
properties: {
supplierId: { type: "string", description: "Supplier ID" },
action: {
type: "string",
enum: ["accept", "reject"],
description: "Action to perform by supplier",
},
},
required: ["supplierId", "action"],
},
security: [{ basicAuth: [] }],
},
// preHandler: fastify.auth([fastify.authenticate]),
handler: supplierController.respondToRecurringRequestedBooking,
});
next();
}

Loading…
Cancel
Save