| 1234567891011121314151617181920212223242526272829303132 |
- import {test} from 'node:test';
- import assert from 'node:assert/strict';
- import {readFileSync} from 'node:fs';
- import {PGlite} from '@electric-sql/pglite';
- test('read recovery preserves corrected receipts, tenant fields and function results; rerun is safe',async()=>{
- const db=new PGlite();try{
- const rewards=readFileSync(new URL('../sql/review-rewards.sql',import.meta.url),'utf8');
- const table=name=>rewards.match(new RegExp('CREATE TABLE IF NOT EXISTS "'+name+'" \\([^]*?\\n\\);'))[0];
- await db.exec(table('ReviewReward')+`;ALTER TABLE "ReviewReward" ADD COLUMN "ineligibleReason" text NOT NULL DEFAULT '';`);
- await db.exec(table('ReviewRewardCorrection'));
- await db.exec(`CREATE FUNCTION xs_payroll_sources(text) RETURNS SETOF jsonb LANGUAGE sql STABLE AS $$ SELECT '{"amount":1}'::jsonb $$;
- CREATE FUNCTION xs_payroll_source_version(text) RETURNS text LANGUAGE sql STABLE AS $$ SELECT 'unchanged'::text $$;
- CREATE FUNCTION xs_payroll_cutoff_snapshot(text,text) RETURNS jsonb LANGUAGE sql STABLE AS $$ SELECT '{"approved":false}'::jsonb $$;
- INSERT INTO "ReviewReward" ("objectId",company,"taskId","coachId","completedAt","incomeMonth",status,amount,"ineligibleReason") VALUES
- ('earned','a','t1',1,now(),'2026-10','earned',1,''),('corrected','a','t2',1,now(),'2026-10','earned',1,''),
- ('overdue','a','t3',1,now(),'2026-09','ineligible',0,'overdue'),('other','b','t4',2,now(),'2026-10','earned',1,'');
- INSERT INTO "ReviewRewardCorrection" ("objectId",company,"rewardId",amount,reason,actor) VALUES ('fix','a','corrected',-1,'核对逾期','admin');
- CREATE VIEW "ReviewRewardIncome" AS SELECT projected.*,r.amount AS "originalAmount",c."objectId" AS "correctionId",c.reason AS "correctionReason",c.amount AS "correctionAmount",c."adjustmentBatchId"
- FROM "ReviewReward" r LEFT JOIN "ReviewRewardCorrection" c ON c.company=r.company AND c."rewardId"=r."objectId"
- CROSS JOIN LATERAL jsonb_populate_record(NULL::"ReviewReward",to_jsonb(r)||jsonb_build_object('amount',r.amount+COALESCE(c.amount,0),'status',CASE WHEN c."objectId" IS NULL THEN r.status ELSE 'ineligible' END,'ineligibleReason',CASE WHEN c."objectId" IS NULL THEN r."ineligibleReason" ELSE 'corrected_overdue' END)) projected;`);
- const sql='SELECT * FROM "ReviewRewardIncome" ORDER BY "objectId"',before=(await db.query(sql)).rows;
- const patch=readFileSync(new URL('../sql/payroll-read-timeout-recovery.sql',import.meta.url),'utf8');
- for(let i=0;i<2;i++){
- await db.exec(patch);assert.deepEqual((await db.query(sql)).rows,before);
- assert.equal((await db.query("SELECT xs_payroll_source_version('a') v")).rows[0].v,'unchanged');
- assert.deepEqual((await db.query('SELECT "objectId" FROM "ReviewRewardIncome" WHERE company=$1 AND "incomeMonth"=$2 AND status=\'earned\'',['a','2026-10'])).rows,[{objectId:'earned'}]);
- const functions=(await db.query("SELECT proconfig FROM pg_proc WHERE proname IN ('xs_payroll_sources','xs_payroll_source_version','xs_payroll_cutoff_snapshot')")).rows;
- assert.equal(functions.length,3);assert.ok(functions.every(f=>f.proconfig.includes('jit=off')));
- }
- }finally{await db.close();}
- });
|