Files
ihaleist/server/analysis-schema.mjs

51 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const analysisArrayFields = ['qualificationCriteria','criticalRequirements','risksAndPenalties','disqualificationRisks','criticalDetails','itemsAndSpecs','documentChecklist','deadlines','costDrivers','roadmap','questionsForAdministration'];
const stringLists = new Set(['qualificationCriteria','criticalRequirements','disqualificationRisks','costDrivers','questionsForAdministration']);
const shapes = {
itemsAndSpecs: ['name','quantity','note'], documentChecklist: ['document','note'],
risksAndPenalties: ['level','clause','text'], criticalDetails: ['level','title','where','detail','whyItMatters'],
deadlines: ['label','value','note'], roadmap: ['phase','action','owner','timing','output'],
};
const object = v => v && typeof v === 'object' && !Array.isArray(v);
const fail = path => { throw new Error(`Analiz alanının biçimi geçersiz: ${path}`); };
const text = (v,path) => { if (v != null && typeof v !== 'string') fail(path); };
const number = (v,path) => { if (v != null && (typeof v !== 'number' || !Number.isFinite(v) || v < 0)) fail(path); };
export function validateAnalysisShape(result) {
if (!object(result)) fail('result');
const issues = [];
for (const field of ['summary','scopeOfWork']) text(result[field],field);
for (const field of analysisArrayFields) {
if (result[field] == null) continue;
if (!Array.isArray(result[field])) fail(field);
result[field].forEach((row,i) => {
const path = `${field}.${i}`;
if (stringLists.has(field)) { if (typeof row !== 'string' || !row.trim()) fail(path); return; }
if (!object(row)) fail(path);
for (const key of shapes[field]) text(row[key],`${path}.${key}`);
if (field === 'itemsAndSpecs') {
if (!row.name?.trim() || !row.quantity?.trim()) issues.push(`${path}: kalem adı veya miktar/birim eksik.`);
if (row.keySpecs != null && (!Array.isArray(row.keySpecs) || row.keySpecs.some(v => typeof v !== 'string'))) fail(`${path}.keySpecs`);
for (const key of ['estimatedUnitPrice','estimatedTotal']) number(row[key],`${path}.${key}`);
}
if (field === 'documentChecklist') {
if (!row.document?.trim() || row.mandatory == null) issues.push(`${path}: belge adı veya zorunluluk bilgisi eksik.`);
if (row.mandatory != null && typeof row.mandatory !== 'boolean') fail(`${path}.mandatory`);
}
if (field === 'roadmap' && row.step != null && (!Number.isInteger(row.step) || row.step < 1)) fail(`${path}.step`);
});
}
if (result.bidAnalysis != null) {
if (!object(result.bidAnalysis)) fail('bidAnalysis');
for (const key of ['estimatedCost','recommendedBid','minBidLimit','maxBidLimit','winProbability']) number(result.bidAnalysis[key],`bidAnalysis.${key}`);
if (result.bidAnalysis.winProbability > 100) fail('bidAnalysis.winProbability');
for (const key of ['competitionLevel','notes']) text(result.bidAnalysis[key],`bidAnalysis.${key}`);
}
if (result.citations != null) {
if (!Array.isArray(result.citations)) fail('citations');
result.citations.forEach((c,i) => {
if (!object(c) || typeof c.path !== 'string' || typeof c.quote !== 'string') fail(`citations.${i}`);
});
}
return issues;
}