mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(accommodations): a second night on the day counts by its check-in
Two bookings on one day used to settle by whichever was seated last, because the other night's stop carries no hour of its own. Its check-in counts now, in the service and in the migration alike.
This commit is contained in:
@@ -31,10 +31,13 @@ export function reseatBookedNights(db: Database.Database): number {
|
||||
JOIN day_accommodations a ON a.id = da.accommodation_id
|
||||
ORDER BY da.day_id, da.order_index, da.id
|
||||
`).all() as Array<{ id: number; day_id: number; check_in: string | null }>;
|
||||
// Another night on the same day counts by its check-in, so two bookings on one
|
||||
// day settle by the clock instead of by whichever was seated last.
|
||||
const dayRows = db.prepare(`
|
||||
SELECT da.id, COALESCE(da.assignment_time, p.place_time) AS at,
|
||||
SELECT da.id, COALESCE(da.assignment_time, p.place_time, other.check_in) AS at,
|
||||
(p.lat IS NOT NULL AND p.lng IS NOT NULL) AS located
|
||||
FROM day_assignments da JOIN places p ON p.id = da.place_id
|
||||
LEFT JOIN day_accommodations other ON other.id = da.accommodation_id
|
||||
WHERE da.day_id = ?
|
||||
ORDER BY da.order_index ASC, da.created_at ASC, da.id ASC
|
||||
`);
|
||||
|
||||
@@ -296,9 +296,12 @@ export class AccommodationsService {
|
||||
if (!checkIn) return 0;
|
||||
// excludeId leaves the row being re-seated out of the chain it is measured
|
||||
// against. Without it a night parked at the end of the day can find itself.
|
||||
// Another booked night on the day counts by its check-in, so two bookings on
|
||||
// one day settle by the clock.
|
||||
const rows = this.db.all<{ order_index: number; at: string | null }>(`
|
||||
SELECT da.order_index, COALESCE(da.assignment_time, p.place_time) AS at
|
||||
SELECT da.order_index, COALESCE(da.assignment_time, p.place_time, other.check_in) AS at
|
||||
FROM day_assignments da JOIN places p ON p.id = da.place_id
|
||||
LEFT JOIN day_accommodations other ON other.id = da.accommodation_id
|
||||
WHERE da.day_id = ? AND da.id != ? ORDER BY da.order_index
|
||||
`, dayId, excludeId ?? -1);
|
||||
let seat = 0;
|
||||
@@ -319,8 +322,9 @@ export class AccommodationsService {
|
||||
private seatedByCheckIn(dayId: number, ownId: number, checkIn: string | null | undefined): boolean {
|
||||
if (!checkIn) return true;
|
||||
const rows = this.db.all<{ id: number; at: string | null }>(`
|
||||
SELECT da.id, COALESCE(da.assignment_time, p.place_time) AS at
|
||||
SELECT da.id, COALESCE(da.assignment_time, p.place_time, other.check_in) AS at
|
||||
FROM day_assignments da JOIN places p ON p.id = da.place_id
|
||||
LEFT JOIN day_accommodations other ON other.id = da.accommodation_id
|
||||
WHERE da.day_id = ? ORDER BY da.order_index
|
||||
`, dayId);
|
||||
const own = rows.findIndex(row => row.id === ownId);
|
||||
|
||||
@@ -177,6 +177,18 @@ describe('booked night reseat', () => {
|
||||
expect(vias(db).map((v) => v.id)).not.toContain(afterA);
|
||||
});
|
||||
|
||||
it('RESEAT-010: two nights on one day settle by their check-ins', () => {
|
||||
const db = freshDb();
|
||||
const [later, earlier] = [place(db, 'Rue de Paris'), place(db, 'Brandenburger Tor')];
|
||||
stop(db, later, 0, null, night(db, later, '12:00'));
|
||||
stop(db, earlier, 1, null, night(db, earlier, '10:00'));
|
||||
|
||||
reseatBookedNights(db);
|
||||
|
||||
expect(order(db)).toEqual([earlier, later]);
|
||||
expect(reseatBookedNights(db)).toBe(0);
|
||||
});
|
||||
|
||||
it('RESEAT-008: runs again without moving anything', () => {
|
||||
const db = freshDb();
|
||||
const [fuel, hotel] = [place(db, 'Aral'), place(db, 'Rostock')];
|
||||
|
||||
@@ -743,6 +743,20 @@ describe('the day stop a booking implies', () => {
|
||||
expect(stopsOn(day.id).map(a => a.place_id)).toEqual([afternoon.id, hotel.id]);
|
||||
});
|
||||
|
||||
it('ACC-022i a second night on the day counts by its check-in', () => {
|
||||
const { user } = createUser(testDb);
|
||||
const trip = createTrip(testDb, user.id);
|
||||
const day = createDay(testDb, trip.id);
|
||||
const [noon, morning] = ['Rue de Paris', 'Brandenburger Tor'].map(name => createPlace(testDb, trip.id, { name }));
|
||||
svc.createAccommodation(trip.id, { place_id: noon.id, start_day_id: day.id, end_day_id: day.id, check_in: '12:00' });
|
||||
svc.createAccommodation(trip.id, { place_id: morning.id, start_day_id: day.id, end_day_id: day.id, check_in: '10:00' });
|
||||
expect(stopsOn(day.id).map(a => a.place_id)).toEqual([morning.id, noon.id]);
|
||||
|
||||
const evening = createPlace(testDb, trip.id, { name: 'Late' });
|
||||
svc.createAccommodation(trip.id, { place_id: evening.id, start_day_id: day.id, end_day_id: day.id, check_in: '18:00' });
|
||||
expect(stopsOn(day.id).map(a => a.place_id)).toEqual([morning.id, noon.id, evening.id]);
|
||||
});
|
||||
|
||||
it('ACC-022h an edit that leaves the check-in alone still corrects a night the clocks contradict', () => {
|
||||
// Dragged behind a stop pinned to the afternoon, with a check-in at ten: a change of
|
||||
// notes puts it back ahead of that stop, because a night sitting after an afternoon it
|
||||
|
||||
Reference in New Issue
Block a user