Rework entry types: merge hotel into stay, transport with modes, auto-transport
- Type set is now activity/stay/transport/flight/rental/note; hotel, travel and immigration are removed with idempotent startup data migrations (hotel->stay, travel->transport, immigration->activity with flag prefix) - Transport entries carry an optional mode (train/bus/ferry/taxi/drive/other) that drives the chip/map icon; route stops expose transport_mode - Creating a stay auto-creates a bridging transport to its neighbouring stays unless a transport/flight already covers the gap (one-shot) - Summary: transports count replaces hotels/travelLegs
This commit is contained in:
+8
-8
@@ -82,12 +82,12 @@ test('costs: equal split with payer produces net balances and a settlement', asy
|
||||
const ben = await createAccount();
|
||||
const trip = await costTrip(anna, [ben]);
|
||||
|
||||
// anna pays 950 (hotel), ben pays 500 (travel); both split equally between the two.
|
||||
// anna pays 950 (stay), ben pays 500 (transport); both split equally between the two.
|
||||
await anna.agent.post(`/api/trips/${trip.id}/entries`).send({
|
||||
date: '2026-08-01', type: 'hotel', title: 'Hotel', price: 950, paid_by: anna.user.id,
|
||||
date: '2026-08-01', type: 'stay', title: 'Hotel', price: 950, paid_by: anna.user.id,
|
||||
});
|
||||
await anna.agent.post(`/api/trips/${trip.id}/entries`).send({
|
||||
date: '2026-08-02', type: 'travel', title: 'Van', price: 500, paid_by: ben.user.id,
|
||||
date: '2026-08-02', type: 'transport', title: 'Van', price: 500, paid_by: ben.user.id,
|
||||
});
|
||||
|
||||
const res = await anna.agent.get(`/api/trips/${trip.id}/costs`);
|
||||
@@ -95,7 +95,7 @@ test('costs: equal split with payer produces net balances and a settlement', asy
|
||||
const c = res.body;
|
||||
assert.equal(c.currency, 'USD');
|
||||
assert.equal(c.totalCost, 1450);
|
||||
assert.deepEqual(c.byType, { hotel: 950, travel: 500 });
|
||||
assert.deepEqual(c.byType, { stay: 950, transport: 500 });
|
||||
assert.equal(c.unassigned, 0);
|
||||
|
||||
const a = findUser(c, anna.user.id);
|
||||
@@ -159,7 +159,7 @@ test('costs: participants subset only splits among the chosen members', async ()
|
||||
|
||||
// 90 split equally between anna & ben only (carol excluded), anna pays.
|
||||
await anna.agent.post(`/api/trips/${trip.id}/entries`).send({
|
||||
date: '2026-08-01', type: 'travel', title: 'Taxi', price: 90, paid_by: anna.user.id,
|
||||
date: '2026-08-01', type: 'transport', title: 'Taxi', price: 90, paid_by: anna.user.id,
|
||||
participants: [anna.user.id, ben.user.id],
|
||||
});
|
||||
|
||||
@@ -179,13 +179,13 @@ test('costs: equal with no payer accumulates into unassigned', async () => {
|
||||
const trip = await costTrip(anna, [ben]);
|
||||
|
||||
await anna.agent.post(`/api/trips/${trip.id}/entries`).send({
|
||||
date: '2026-08-01', type: 'hotel', title: 'Hotel', price: 200, // paid_by omitted (null)
|
||||
date: '2026-08-01', type: 'stay', title: 'Hotel', price: 200, // paid_by omitted (null)
|
||||
});
|
||||
|
||||
const c = (await anna.agent.get(`/api/trips/${trip.id}/costs`)).body;
|
||||
assert.equal(c.totalCost, 200);
|
||||
assert.equal(c.unassigned, 200);
|
||||
assert.deepEqual(c.byType, { hotel: 200 });
|
||||
assert.deepEqual(c.byType, { stay: 200 });
|
||||
for (const u of c.perUser) {
|
||||
assert.deepEqual([u.share, u.paid, u.net], [100, 0, -100]);
|
||||
}
|
||||
@@ -207,7 +207,7 @@ test('computeCosts: greedy settlement matches largest debtor with largest credit
|
||||
const c = computeCosts({
|
||||
currency: 'USD',
|
||||
members,
|
||||
entries: [{ type: 'hotel', price: 300, paid_by: 1, split_mode: 'equal', participants: [] }],
|
||||
entries: [{ type: 'stay', price: 300, paid_by: 1, split_mode: 'equal', participants: [] }],
|
||||
});
|
||||
assert.equal(c.totalCost, 300);
|
||||
assert.equal(findUser(c, 1).displayName, 'brave-otter');
|
||||
|
||||
Reference in New Issue
Block a user