updates on the bookings page and updated ai and more thngs

This commit is contained in:
2026-09-11 11:20:38 +05:30
parent 1caa7b71a9
commit 49ee0c5076
40 changed files with 5796 additions and 359 deletions

View File

@@ -0,0 +1,215 @@
/**
* Build the logistics bulk-upload test sheet.
*
* node scripts/makeLogisticsTestSheet.cjs
*
* The tenant's own export (tests/fixtures/jayanthi-kitchen-route.xls) is 13
* lunch drops inside Coimbatore. Every one of them is hyperlocal, so uploading
* it exercises none of the base-handover path — no parcel in that file is ever
* routed through a base, and `next_action` never leaves `deliver`.
*
* This sheet keeps that file's exact column titles, so it travels through the
* same header map and the same page code, and changes only the one thing that
* decides routing: WHERE THE PARCEL IS GOING.
*
* The rule it is built against (backend, isHyperlocalBooking):
*
* • both pincodes present → same first 3 digits is hyperlocal, different is
* routed through a base. The prefix decides
* outright; distance does not get a vote.
* • a pincode missing → fall back to straight-line distance, ≤30 km is
* hyperlocal.
* • neither resolvable → routed through a base, which is the safe answer.
*
* Two columns are added that the tenant's file does not carry — Receiver
* Pincode and Receiver City. Both are already in SHEET_HEADER_MAP
* (receiverpincode → postcode, receivercity → city), so this is not a new
* format: it is the same format with columns the map already knows filled in.
* Without a pincode every row would land on the distance fallback, and the
* prefix rule — the one that actually decides intercity — would never run.
*/
const fs = require('node:fs');
const path = require('node:path');
const XLSX = require('xlsx');
const SENDER = {
name: 'Jayanthi',
phone: 7708733769,
address: 'Edayarpalayam, Coimbatore, Tamil Nadu 641025'
};
const PICKUP_DATE = 'Sep 02, 2026';
/**
* expect: what the backend should decide for the row, and why. Not a column —
* it is carried here so the fixture and the test assertions cannot drift, and
* it is written into a "Notes" column on the sheet so an operator running this
* by hand can see what they are meant to be looking at.
*/
const ROWS = [
// ---- Customer → Base. Different postal area, so the rider collects and
// carries it to a base instead of to the receiver. This is the whole
// point of the file.
{
name: 'Suresh Kumar', phone: 9840112233, alt: 9840112234,
address: 'Flat 3B, 21 NSC Bose Road, Parrys, Chennai', city: 'Chennai', pincode: '600001',
lat: 13.091, lng: 80.285, item: 'Documents envelope', qty: 1, cash: 0,
expect: 'base handover — Coimbatore 641 to Chennai 600'
},
{
name: 'Priya Raghavan', phone: 9840223344, alt: 9840223345,
address: '14 Cheran Street, Raja Annamalai Puram, Chennai', city: 'Chennai', pincode: '600028',
lat: 13.018, lng: 80.256, item: 'Spare parts carton', qty: 2, cash: 0,
expect: 'base handover — Coimbatore 641 to Chennai 600'
},
{
name: 'Anil Reddy', phone: 9848334455, alt: 9848334456,
address: 'Plot 42, Gachibowli, Hyderabad', city: 'Hyderabad', pincode: '500081',
lat: 17.44, lng: 78.3489, item: 'Textile samples', qty: 3, cash: 0,
expect: 'base handover — interstate, Coimbatore to Hyderabad'
},
{
name: 'Meera Krishnan', phone: 9848445566, alt: 9848445567,
address: 'Tower B, Financial District, Nanakramguda, Hyderabad', city: 'Hyderabad', pincode: '500032',
lat: 17.4156, lng: 78.3378, item: 'Legal documents', qty: 1, cash: 450,
expect: 'base handover with COD — cash must survive the base leg'
},
{
name: 'Rahul Menon', phone: 9880556677, alt: 9880556678,
address: '9 Brigade Road, MG Road, Bengaluru', city: 'Bengaluru', pincode: '560001',
lat: 12.975, lng: 77.606, item: 'Electronics accessories', qty: 2, cash: 0,
expect: 'base handover — interstate, Coimbatore to Bengaluru'
},
{
name: 'Divya Nair', phone: 9880667788, alt: 9880667789,
address: 'Prestige Shantiniketan, Whitefield, Bengaluru', city: 'Bengaluru', pincode: '560066',
lat: 12.9698, lng: 77.75, item: 'Gift hamper', qty: 1, cash: 1200,
expect: 'base handover with COD'
},
{
name: 'Karthik Subramani', phone: 9843778899, alt: 9843778890,
address: '5 East Veli Street, Madurai', city: 'Madurai', pincode: '625001',
lat: 9.9195, lng: 78.119, item: 'Temple prasadam box', qty: 1, cash: 0,
expect: 'base handover — same state, different postal area still routes via a base'
},
{
name: 'Lakshmi Devi', phone: 9842889900, alt: 9842889901,
address: '18 Cherry Road, Salem', city: 'Salem', pincode: '636001',
lat: 11.664, lng: 78.146, item: 'Handloom bundle', qty: 2, cash: 0,
expect: 'base handover — same state, different postal area'
},
// ---- Customer → Customer. Same postal area, so the collecting rider carries
// it straight to the receiver and no base is involved. These rows are
// the control group: if one of them routes to a base, the prefix rule
// has broken.
{
name: 'Ganesh Iyer', phone: 9994001122, alt: 9994001123,
address: '22 Avinashi Road, Peelamedu, Coimbatore', city: 'Coimbatore', pincode: '641004',
lat: 11.029, lng: 76.993, item: 'Lunch box', qty: 1, cash: 0,
expect: 'direct to customer — same 641 area'
},
{
name: 'Revathi Balaji', phone: 9994112233, alt: 9994112234,
address: '7 Cross Cut Road, Gandhipuram, Coimbatore', city: 'Coimbatore', pincode: '641012',
lat: 11.018, lng: 76.966, item: 'Lunch box', qty: 2, cash: 260,
expect: 'direct to customer with COD — same 641 area'
},
{
name: 'Vignesh Murugan', phone: 9994223344, alt: 9994223345,
address: '3/74 Nethaji Street, Edayarpalayam, Coimbatore', city: 'Coimbatore', pincode: '641025',
lat: 11.008, lng: 76.928, item: 'Lunch box', qty: 1, cash: 0,
expect: 'direct to customer — receiver shares the sender pincode'
},
{
name: 'Anitha Selvam', phone: 9994334455, alt: 9994334456,
address: '11 DB Road, Saibaba Colony, Coimbatore', city: 'Coimbatore', pincode: '641038',
lat: 11.023, lng: 76.945, item: 'Bakery order', qty: 3, cash: 0,
expect: 'direct to customer — same 641 area'
},
// ---- The fallback rule. A pincode is missing, so the decision falls to the
// straight-line distance instead. Both outcomes are represented, because
// a fallback that only ever answers one way is not being tested.
{
name: 'Mohan Das', phone: 9995445566, alt: 9995445567,
address: 'Near Hope College signal, Coimbatore', city: 'Coimbatore', pincode: '',
lat: 11.05, lng: 77.01, item: 'Stationery pack', qty: 1, cash: 0,
expect: 'direct to customer — no pincode, but ~8 km falls inside the 30 km fallback'
},
{
name: 'Sridhar Venkat', phone: 9995556677, alt: 9995556678,
address: 'Opposite Central Station, Chennai', city: 'Chennai', pincode: '',
lat: 13.0827, lng: 80.2707, item: 'Machine component', qty: 1, cash: 0,
expect: 'base handover — no pincode, but ~430 km is far outside the fallback'
},
{
name: 'Bhavani Shankar', phone: 9995667788, alt: 9995667789,
address: 'T Nagar, Chennai', city: 'Chennai', pincode: '64',
lat: 13.06, lng: 80.24, item: 'Fabric roll', qty: 1, cash: 0,
expect: 'base handover — a 2-digit pincode is unusable, so distance decides'
},
// ---- The case that proves the prefix rule outranks distance. Pollachi is
// ~40 km from Coimbatore — closer than plenty of runs the console treats
// as local — but 642 is a different postal area, so it goes via a base.
{
name: 'Ramesh Palanisamy', phone: 9995778899, alt: 9995778890,
address: '2 Mahalingapuram Road, Pollachi', city: 'Pollachi', pincode: '642001',
lat: 10.658, lng: 77.008, item: 'Agricultural samples', qty: 2, cash: 0,
expect: 'base handover — nearby, but 642 is a different area and the prefix decides'
}
];
const HEADERS = [
'Pickup Date (YYYY-MMM-DD )',
'Sender Name*',
'Sender Phone*',
'Sender Address*',
'Receiver Name*',
'Receiver Phone',
'Receiver Alternate Phone*',
'Receiver Full Address',
'Receiver City',
'Receiver Pincode',
'Receiver Latitude',
'Receiver Longitude',
'Item Description*',
'Quantity',
'Collect Cash',
'Expected Routing (not read by the app)'
];
const sheetRows = ROWS.map((r) => ({
'Pickup Date (YYYY-MMM-DD )': PICKUP_DATE,
'Sender Name*': SENDER.name,
'Sender Phone*': SENDER.phone,
'Sender Address*': SENDER.address,
'Receiver Name*': r.name,
'Receiver Phone': r.phone,
'Receiver Alternate Phone*': r.alt,
'Receiver Full Address': r.address,
'Receiver City': r.city,
'Receiver Pincode': r.pincode,
'Receiver Latitude': r.lat,
'Receiver Longitude': r.lng,
'Item Description*': r.item,
Quantity: r.qty,
'Collect Cash': r.cash,
'Expected Routing (not read by the app)': r.expect
}));
const ws = XLSX.utils.json_to_sheet(sheetRows, { header: HEADERS });
ws['!cols'] = HEADERS.map((h) => ({ wch: Math.min(46, Math.max(14, h.length + 2)) }));
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Doormile_Logistics_Test');
const targets = process.argv.slice(2);
if (targets.length === 0) targets.push(path.join(__dirname, '..', 'tests', 'fixtures', 'doormile-logistics-test.xlsx'));
targets.forEach((out) => {
fs.mkdirSync(path.dirname(out), { recursive: true });
XLSX.writeFile(wb, out);
console.log(`wrote ${sheetRows.length} rows → ${out}`);
});