batch-cancel-guard.test.mjs 2.0 KB

1234567891011121314
  1. import {test} from 'node:test';import assert from 'node:assert/strict';import {readFileSync} from 'node:fs';import {PGlite} from '@electric-sql/pglite';
  2. test('批量取消要求未开始且版本匹配,防止选择后已上课的预约被取消',async()=>{
  3. const db=new PGlite();try{
  4. await db.exec(`CREATE TABLE "CommonModel"(company text,"objectId" text,"modelId" numeric,"itemId" numeric,"updatedAt" timestamptz,status numeric);
  5. CREATE TABLE "CourseAppointment"(company text,id numeric,dszt text);
  6. INSERT INTO "CommonModel" VALUES('co','one',54,1,'2026-11-04 10:00+08',99),('co','active',54,2,'2026-11-04 10:00+08',99);
  7. INSERT INTO "CourseAppointment" VALUES('co',1,'0'),('co',2,'10');
  8. CREATE FUNCTION xs_schedule_cancel(co text,aid text,restore boolean,actor text,reason text,expected text) RETURNS jsonb LANGUAGE plpgsql AS $$DECLARE v timestamptz;BEGIN SELECT "updatedAt" INTO v FROM "CommonModel" WHERE company=co AND "objectId"=aid;IF date_trunc('milliseconds',v)<>expected::timestamptz THEN RAISE EXCEPTION '预约已变更';END IF;UPDATE "CommonModel" SET status=-2 WHERE company=co AND "objectId"=aid;RETURN jsonb_build_object('targetId',aid);END$$;`);
  9. const src=readFileSync(new URL('../sql/member-enrollment.sql',import.meta.url),'utf8'),def=src.match(/CREATE OR REPLACE FUNCTION xs_schedule_cancel_unstarted\([\s\S]*?\$\$;/)?.[0];assert.ok(def,'缺少未开始预约保护函数');await db.exec(def);
  10. const run=(id,version='2026-11-04T02:00:00.000Z')=>db.query('SELECT xs_schedule_cancel_unstarted($1,$2,$3,$4,$5)',['co',id,'manager','批量调整',version]);
  11. await assert.rejects(run('active'),/未开始/);await assert.rejects(run('one',''),/版本/);await assert.rejects(run('one','2026-11-03'),/变更/);
  12. await run('one');assert.equal((await db.query('SELECT status FROM "CommonModel" WHERE "objectId"=\'one\'')).rows[0].status,'-2');assert.equal((await db.query('SELECT status FROM "CommonModel" WHERE "objectId"=\'active\'')).rows[0].status,'99');
  13. }finally{await db.close();}
  14. });