|
|
@@ -26,7 +26,10 @@ before(async()=>{
|
|
|
INSERT INTO "Node" VALUES ('co',100,8,'词表',99),('co',101,8,'空词表',99);
|
|
|
INSERT INTO "CommonModel" ("objectId","company","nodeId","modelId","status") SELECT 'word-'||i,'co',100,52,99 FROM generate_series(1,200) i;`);
|
|
|
await db.exec(`ALTER TABLE "Node" ADD COLUMN "sourceKey" text, ADD COLUMN "createdAt" timestamptz;`);
|
|
|
- await db.exec(sql);
|
|
|
+ const oldVersionSql=sql.replaceAll(/date_trunc\('milliseconds',(old_c|c)\."updatedAt"\)/g,'$1."updatedAt"');
|
|
|
+ await db.exec(oldVersionSql);
|
|
|
+ const precisionPatch=readFileSync(new URL('../sql/schedule-version-precision.sql',import.meta.url),'utf8');
|
|
|
+ await db.exec(precisionPatch);await db.exec(precisionPatch);
|
|
|
const workflow=readFileSync(new URL('../sql/lesson-workflow.sql',import.meta.url),'utf8');
|
|
|
for(const name of ['xs_start_appointment_for_actor','xs_admin_lesson_correction'])await db.exec(workflow.match(new RegExp('CREATE OR REPLACE FUNCTION '+name+'[\\s\\S]*?END \\$\\$;'))[0]);
|
|
|
});
|
|
|
@@ -84,9 +87,15 @@ test('排课保存、修改、取消恢复均同步预留,重试不重复',asy
|
|
|
const entry=scheduleEntry(b,'2030-01-01 10:00');const saved=await saveSchedule([entry],'schedule-001');const again=await saveSchedule([entry],'schedule-001');assert.deepEqual(again,saved);
|
|
|
const aid=saved.targetIds[0];assert.equal((await one('SELECT "state" FROM "CourseCreditReservation" WHERE "appointmentId"=$1',[aid])).state,'reserved');
|
|
|
await assert.rejects(saveSchedule([scheduleEntry(b,'2030-01-01 10:10')],'schedule-conflict'),/冲突/);
|
|
|
- await saveSchedule([scheduleEntry(b,'2030-01-01 11:00')],'schedule-update',aid);
|
|
|
- await query('SELECT xs_schedule_cancel(\'co\',$1,false,\'admin\',\'测试取消\')',[aid]);assert.equal((await one('SELECT "state" FROM "CourseCreditReservation" WHERE "appointmentId"=$1',[aid])).state,'released');
|
|
|
- await query('SELECT xs_schedule_cancel(\'co\',$1,true,\'admin\',\'测试恢复\')',[aid]);assert.equal((await one('SELECT "state" FROM "CourseCreditReservation" WHERE "appointmentId"=$1',[aid])).state,'reserved');
|
|
|
+ // Reproduce actual PostgreSQL microseconds round-tripped through a JSON Date.
|
|
|
+ await query('UPDATE "CommonModel" SET "updatedAt"=\'2026-10-15T13:34:39.758987Z\' WHERE "objectId"=$1',[aid]);
|
|
|
+ const version=async()=>(await one('SELECT "updatedAt" FROM "CommonModel" WHERE "objectId"=$1',[aid])).updatedAt.toISOString();
|
|
|
+ const initial=await version();assert.equal(initial,'2026-10-15T13:34:39.758Z');
|
|
|
+ await saveSchedule([scheduleEntry(b,'2030-01-01 11:00')],'schedule-update',aid,initial);
|
|
|
+ await assert.rejects(saveSchedule([scheduleEntry(b,'2030-01-01 12:00')],'schedule-stale',aid,initial),/已修改/);
|
|
|
+ await assert.rejects(query('SELECT xs_schedule_cancel(\'co\',$1,false,\'admin\',\'测试取消\',$2)',[aid,initial]),/已变更/);
|
|
|
+ await query('SELECT xs_schedule_cancel(\'co\',$1,false,\'admin\',\'测试取消\',$2)',[aid,await version()]);assert.equal((await one('SELECT "state" FROM "CourseCreditReservation" WHERE "appointmentId"=$1',[aid])).state,'released');
|
|
|
+ await query('SELECT xs_schedule_cancel(\'co\',$1,true,\'admin\',\'测试恢复\',$2)',[aid,await version()]);assert.equal((await one('SELECT "state" FROM "CourseCreditReservation" WHERE "appointmentId"=$1',[aid])).state,'reserved');
|
|
|
await query('SELECT xs_schedule_cancel(\'co\',$1,false,\'admin\',\'测试取消\')',[aid]);
|
|
|
});
|
|
|
test('批量排课超余额整体回滚,不留下半张预约或预留',async()=>{
|