135 lines
5.9 KiB
JavaScript
135 lines
5.9 KiB
JavaScript
import { makeLocationFilter, ZONE_RADIUS_KM } from '@/lib/locationScope';
|
|
|
|
/**
|
|
* Control X's hub picker.
|
|
*
|
|
* Its `applocationid` was destructured out of the fetchDeliveries query key and
|
|
* then ignored — the same silent no-op the folder's CLAUDE.md records for
|
|
* startdate/enddate, and it survived the fix. Picking a hub rebuilt the key,
|
|
* refetched, and returned the same nationwide rows, so the header read
|
|
* "Coimbatore Neptune Hub" over a map drawing a Bangalore rider on Mysore Road.
|
|
*
|
|
* The hubs below are the real rows, including `Coimbatore Test Hub` at 0,0 —
|
|
* the Gulf of Guinea — which must never be used as a centre.
|
|
*/
|
|
const HUBS = [
|
|
{ hubid: 1, hubname: 'Coimbatore Jupiter Hub', applocationid: 1, latitude: 11.0168, longitude: 76.9558, pincode: '641012' },
|
|
{ hubid: 2, hubname: 'Coimbatore Neptune Hub', applocationid: 1, latitude: 11.0301, longitude: 77.0034, pincode: '641004' },
|
|
{ hubid: 17, hubname: 'Coimbatore Test Hub', applocationid: 1, latitude: 0, longitude: 0, pincode: '641099' },
|
|
{ hubid: 5, hubname: 'Bangalore Earth Hub', applocationid: 3, latitude: 12.9352, longitude: 77.6244, pincode: '560034' },
|
|
{ hubid: 11, hubname: 'Bangalore Whitefield Hub', applocationid: 3, latitude: 12.9698, longitude: 77.7499, pincode: '560066' },
|
|
];
|
|
|
|
const COIMBATORE = 1;
|
|
const BANGALORE = 3;
|
|
|
|
// DM-626241 as fetchDeliveries normalises it: Koramangala → Bangalore University.
|
|
const bangaloreRun = (over = {}) => ({
|
|
bookingid: 11, orderid: 'DM-626241', servicinghubid: 5,
|
|
pickuplatitude: 12.9352, pickuplongitude: 77.6244,
|
|
deliverylatitude: 12.94393, deliverylongitude: 77.50918,
|
|
...over,
|
|
});
|
|
|
|
const coimbatoreRun = (over = {}) => ({
|
|
bookingid: 9, orderid: 'DM-956478', servicinghubid: 1,
|
|
pickuplatitude: 11.0168, pickuplongitude: 76.9558,
|
|
deliverylatitude: 11.0183, deliverylongitude: 76.9680,
|
|
...over,
|
|
});
|
|
|
|
describe('the bug this closes', () => {
|
|
it('a Bangalore run does not appear under Coimbatore', () => {
|
|
const inCoimbatore = makeLocationFilter(HUBS, COIMBATORE);
|
|
expect(inCoimbatore(bangaloreRun())).toBe(false);
|
|
});
|
|
|
|
it('and still appears under Bangalore', () => {
|
|
const inBangalore = makeLocationFilter(HUBS, BANGALORE);
|
|
expect(inBangalore(bangaloreRun())).toBe(true);
|
|
});
|
|
|
|
it('a Coimbatore run appears under Coimbatore and not Bangalore', () => {
|
|
expect(makeLocationFilter(HUBS, COIMBATORE)(coimbatoreRun())).toBe(true);
|
|
expect(makeLocationFilter(HUBS, BANGALORE)(coimbatoreRun())).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('"All locations" is not a filter', () => {
|
|
it.each([0, '0', '', null, undefined, 'nonsense'])('%p returns null', (id) => {
|
|
expect(makeLocationFilter(HUBS, id)).toBeNull();
|
|
});
|
|
|
|
it('a city with no hubs fails open rather than emptying the board', () => {
|
|
// A blank board reads as "no work today". That is the more expensive
|
|
// mistake than showing too much, so an unresolvable picker shows all.
|
|
expect(makeLocationFilter(HUBS, 99)).toBeNull();
|
|
expect(makeLocationFilter([], COIMBATORE)).toBeNull();
|
|
expect(makeLocationFilter(null, COIMBATORE)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('how a row is placed', () => {
|
|
it('by the hub it names, with no coordinates at all', () => {
|
|
const inBangalore = makeLocationFilter(HUBS, BANGALORE);
|
|
expect(inBangalore({ orderid: 'X', pickuphubid: 11 })).toBe(true);
|
|
expect(makeLocationFilter(HUBS, COIMBATORE)({ orderid: 'X', pickuphubid: 11 })).toBe(false);
|
|
});
|
|
|
|
it('by either end of the journey, not just the pickup', () => {
|
|
// A run that collects in Coimbatore and delivers there is Coimbatore's
|
|
// work whichever end you look at; one that only arrives is too.
|
|
const inCoimbatore = makeLocationFilter(HUBS, COIMBATORE);
|
|
const inbound = { orderid: 'IN', pickuplatitude: 12.9352, pickuplongitude: 77.6244,
|
|
deliverylatitude: 11.0168, deliverylongitude: 76.9558 };
|
|
expect(inCoimbatore(inbound)).toBe(true);
|
|
});
|
|
|
|
it('a stop just outside the radius does not belong', () => {
|
|
const inBangalore = makeLocationFilter(HUBS, BANGALORE);
|
|
// ~0.01 degree of latitude is ~1.1km, so 0.5 degrees is ~55km north.
|
|
const farAway = { orderid: 'FAR', pickuplatitude: 13.45, pickuplongitude: 77.6244,
|
|
deliverylatitude: 13.46, deliverylongitude: 77.6244 };
|
|
expect(inBangalore(farAway)).toBe(false);
|
|
});
|
|
|
|
it('the radius is the one ZoneContext uses', () => {
|
|
expect(ZONE_RADIUS_KM).toBe(35);
|
|
});
|
|
});
|
|
|
|
describe('a hub at 0,0 is not a centre', () => {
|
|
it('Coimbatore Test Hub does not pull the Gulf of Guinea into Coimbatore', () => {
|
|
// hub 17 is latitude 0, longitude 0 in the live data. Treated as a real
|
|
// point it would claim everything within 35km of the equator's origin.
|
|
const inCoimbatore = makeLocationFilter(HUBS, COIMBATORE);
|
|
expect(inCoimbatore({ orderid: 'NULL_ISLAND', pickuplatitude: 0.1, pickuplongitude: 0.1,
|
|
deliverylatitude: 0.1, deliverylongitude: 0.1 })).toBe(false);
|
|
});
|
|
|
|
it('but its hub id still places a row, since the id is not a guess', () => {
|
|
expect(makeLocationFilter(HUBS, COIMBATORE)({ orderid: 'T', servicinghubid: 17 })).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('a row nobody can place stays visible', () => {
|
|
it('no hub id and no usable coordinates — kept under every city', () => {
|
|
// Dropping it would remove it from ALL cities at once, with nothing on
|
|
// screen to say it had been hidden. That is the failure mode this whole
|
|
// area keeps producing, and it is worse than one stray row.
|
|
const orphan = { orderid: 'ORPHAN' };
|
|
expect(makeLocationFilter(HUBS, COIMBATORE)(orphan)).toBe(true);
|
|
expect(makeLocationFilter(HUBS, BANGALORE)(orphan)).toBe(true);
|
|
});
|
|
|
|
it('a row with 0,0 coordinates counts as unplaceable, not as an address', () => {
|
|
const unpinned = { orderid: 'ZERO', pickuplatitude: 0, pickuplongitude: 0,
|
|
deliverylatitude: 0, deliverylongitude: 0 };
|
|
expect(makeLocationFilter(HUBS, COIMBATORE)(unpinned)).toBe(true);
|
|
});
|
|
|
|
it('a null row is not a row', () => {
|
|
expect(makeLocationFilter(HUBS, COIMBATORE)(null)).toBe(false);
|
|
});
|
|
});
|