feat: add passenger settings and fare configuration with validation

This commit is contained in:
2026-10-12 20:35:33 +03:00
parent e959f55ea1
commit f57f1d7d22
8 changed files with 138 additions and 7 deletions

View File

@@ -59,3 +59,46 @@ test('night preferences validate, survive updates and migrate old stored device
await service.update(d.id,1,{name:'Night',revision:1,settings:{...defaults,nightMode:'off',nightWakeMinutes:45}},1);
const saved=(await service.status(p.token)).device;assert.equal(saved.settings.nightMode,'off');assert.equal(saved.settings.nightWakeMinutes,45);assert.equal(saved.revision,2);
});
test('transliteration migrates old devices, validates booleans and survives a remote update', async () => {
const repo = memoryRepository(), service = createBoardDeviceService(repo);
const pairing = await service.start({});
const device = await service.claim(1, { code: pairing.code, name: 'Latin', settings: defaults }, 1);
delete repo.devices.get(device.id).settings.journeyTranslitEnabled;
assert.equal((await service.status(pairing.token)).device.settings.journeyTranslitEnabled, false);
assert.equal((await service.list(1))[0].settings.journeyTranslitEnabled, false);
for (const flag of ['true', 1, null]) assert.throws(() => validSettings({ ...defaults, journeyTranslitEnabled: flag }), e => e.status === 400);
await service.update(device.id, 1, { name: 'Latin', revision: 1, settings: { ...defaults, journeyTranslitEnabled: true } }, 1);
const saved = (await service.status(pairing.token)).device;
assert.equal(saved.settings.journeyTranslitEnabled, true);
assert.equal(saved.revision, 2);
});
test('passenger configuration validates shape and city/stop/route identity before consuming a code', async () => {
const service = createBoardDeviceService(memoryRepository()), p = await service.start({});
const rule = { routeId: 1, price: 'Особый тариф', payment: 'Подтверждённый способ', checkedAt: '2026-10-11' };
for (const patch of [{ places: [{ stopId: 3, name: 'Другой город' }] }, { places: [{ stopId: 1, name: 'Та же остановка' }] },
{ fareRules: [{ ...rule, routeId: 2 }] }, { fareByType: [{ cityId: 2, type: 'bus', ...rule }] }, { places: null }, { infoFareEnabled: 'true' }]) {
await assert.rejects(service.claim(1, { code: p.code, name: 'Guide', settings: { ...defaults, ...patch } }, 1), e => e.status === 400);
}
await assert.rejects(service.claim(1, { code: p.code, name: 'Guide', settings: null }, 1), e => e.status === 400);
await assert.rejects(service.claim(1, { code:p.code, name:'Guide', settings:{...defaults, fareByType:[{cityId:2,type:'bus',price:'1 BYN',payment:'Наличные',checkedAt:'2026-10-11'}]} }, 1), e => e.code === 'invalid_fare_city');
assert.equal((await service.status(p.token)).state, 'pending');
const d = await service.claim(1, { code: p.code, name: 'Guide', settings: { ...defaults, places: [{ stopId: 2, name: 'Вокзал' }], fareRules: [rule] } }, 1);
const saved = (await service.status(p.token)).device.settings;
assert.equal(saved.places[0].name, 'Вокзал');assert.equal(saved.fareRules[0].price, 'Особый тариф');
await service.update(d.id,1,{name:'Guide',revision:1,settings:{...saved,weatherHintEnabled:false,lastTripNoticeEnabled:false}},1);
assert.equal((await service.status(p.token)).device.settings.weatherHintEnabled,false);
});
test('legacy Polotsk tariffs migrate using the operator confirmation; other cities stay unconfigured', async () => {
for(const cityId of [1,2]) {
const repo=memoryRepository(),service=createBoardDeviceService(repo),p=await service.start({});
const d=await service.claim(cityId,{code:p.code,name:'Legacy',settings:{...defaults,stopId:cityId===1?1:3}},1);
for(const key of ['infoPlacesEnabled','infoFareEnabled','lastTripNoticeEnabled','weatherHintEnabled','places','fareRules','fareByType']) delete repo.devices.get(d.id).settings[key];
const saved=(await service.status(p.token)).device.settings;
assert.equal(saved.lastTripNoticeEnabled,true);assert.deepEqual(saved.places,[]);
assert.equal(saved.fareByType.length,cityId===1?2:0);
if(cityId===1) {assert.equal(saved.fareByType[0].price,'1,05 BYN');assert.equal(saved.fareByType[1].price,'2,10 BYN');assert.equal(saved.fareByType[0].checkedAt,'2026-10-11');}
assert.equal(repo.devices.get(d.id).settings.fareByType,undefined);
}
});