feat: track document and health product preparation checks

This commit is contained in:
2026-09-06 08:42:59 +03:00
parent 465874ebbb
commit e4b02f5dd3
6 changed files with 135 additions and 9 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ before(async()=>{
after(async()=>{if(child){child.kill();await new Promise(r=>child.once('exit',r));}rmSync(dir,{recursive:true,force:true});});
test('HTTP preparation requires auth, persists draft and rejects stale revisions',async()=>{
assert.equal((await request('/api/me/tender-state','GET',null,null)).status,401);
const draft={firma:{firmaUnvan:'QA Laboratuvar'},fiyatlar:{0:'12.50'},gecerlilikGun:'120'};
const draft={firma:{firmaUnvan:'QA Laboratuvar'},priceSchema:1,pricesBySource:{kit1:'12.50'},gecerlilikGun:'120',checks:{products:{kit1:{product:'Test kit',status:'suitable',source:'Teknik 3.2'}},documents:{doc1:{status:'verified',evidence:'Test v1'}}},manualDocuments:[{document:'Yetki',note:'7.1',mandatory:true}],analysisSource:{itemsAndSpecs:[{name:'Kit',quantity:'2 adet'}],documentChecklist:[]}};
const data={key:'2026/1582991',patch:{takipte:true,gorev:{kontrolListesi:[]},bidDraft:draft},snapshot:{id:'ilan-qa',ikn:'2026/1582991'},version:0};
assert.equal((await request('/api/me/tender-state','PUT',data)).status,200);
const read=await request('/api/me/tender-state');assert.deepEqual(read.data.records[data.key].data.bidDraft,draft);
+19
View File
@@ -0,0 +1,19 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {preparationBlockers,documentKey,HEALTH_CHECKS} from '../src/services/preparationChecks.js';
const rows=[{priceKey:'kit1',name:'Kit'}];
const docs=[{document:'Yetki belgesi',mandatory:true,note:'Şartname 7.1'}];
const complete=()=>({documents:{[documentKey(docs[0])]:{status:'verified',evidence:'Yetki v2, süre kontrol edildi, 7.1'}},products:{kit1:{product:'QA model',source:'Teknik 3.2, katalog s4',status:'suitable',...Object.fromEntries(HEALTH_CHECKS.map(([key])=>[key,{status:'notApplicable',evidence:'Doküman ilgili maddesi kapsamında uygulanmıyor'}]))}}});
test('priced rows without document and health review remain incomplete',()=>{
assert.ok(preparationBlockers(rows,[],{}).length>=6);
assert.equal(preparationBlockers(rows,docs,complete()).length,0);
});
test('unsuitable product, missing evidence and mandatory document exemption block readiness',()=>{
const c=complete();c.products.kit1.status='unsuitable';assert.ok(preparationBlockers(rows,docs,c).some(x=>x.includes('uygun değil')));
c.products.kit1.status='suitable';c.products.kit1.uts.evidence=' ';assert.ok(preparationBlockers(rows,docs,c).some(x=>x.includes('ÜTS')));
c.documents[documentKey(docs[0])].status='notApplicable';assert.ok(preparationBlockers(rows,docs,c).some(x=>x.includes('Yetki')));
});
test('changed requirement and changed product row require new checks',()=>{
assert.ok(preparationBlockers(rows,[{...docs[0],note:'Zeyilname 2'}],complete()).length>0);
assert.ok(preparationBlockers([{...rows[0],priceKey:'kit2'}],docs,complete()).length>0);
});