Files
ihaleist/server/tender-quality.mjs
T

43 lines
2.4 KiB
JavaScript
Raw 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.
const norm = v => String(v || '').trim().replace(/\s+/g,' ').toLocaleLowerCase('tr-TR');
export function tenderIdentity(t) {
const ikn = String(t.ikn || '').replace(/\s/g,'');
// Awards from different lots must never be collapsed into one contract.
if (t.durum === 'Sonuçlandı') return `award:${ikn}:${t.kisim ?? t.id}:${norm(t.kazananFirma)}`;
if (/^\d{2}DT\d+$/i.test(ikn)) return `dt:${ikn.toUpperCase()}:${norm(t.kurum)}`;
// Corrections/cancellations remain separate events until their source linkage is verified.
if (/düzeltme|zeyilname|iptal/i.test(t.baslik || '')) return `event:${t.id}`;
return /^\d{4}\/\d+$/.test(ikn) ? `tender:${ikn}` : `source:${t.id}`;
}
export function uniqueTenders(records) {
const found = new Map();
for (const t of records) {
// Kaynaklardan gelen bozuk/null satırlar tüm havuz birleştirmesini düşürmemeli.
if (!t || typeof t !== 'object' || Array.isArray(t) || typeof t.id !== 'string' || !t.id.trim()) continue;
const key = tenderIdentity(t), old = found.get(key);
if (!old) { found.set(key,{...t,sourceIds:[t.id]}); continue; }
const sourceIds = [...new Set([...old.sourceIds,t.id])];
const merged = {...old};
for (const [field,value] of Object.entries(t)) {
if (merged[field] == null || merged[field] === '' || (Array.isArray(merged[field]) && !merged[field].length)) merged[field] = value;
}
if ((t.aciklama || '').length > (old.aciklama || '').length) merged.aciklama = t.aciklama;
found.set(key,{...merged,id:old.id,sourceIds});
}
return [...found.values()];
}
export function announcementFields(text) {
const content = String(text || '');
const result = {aciklama:content};
// EKAP table cells are separated by pipes in extracted text. Keep the
// original announcement intact; normalize separators only for field parsing.
const fields = content.replace(/\s*\|\s*/g, ' ');
const deadline = /Tarih\s*ve\s*Saati\s*:\s*(\d{2}\.\d{2}\.\d{4})\s*[-–]?\s*(\d{2}:\d{2})/i.exec(fields);
if (deadline) { result.tarih = deadline[1]; result.saat = deadline[2]; }
const place = /3\.3\.?\s*[^:]{0,120}:\s*([\s\S]*?)(?=3\.4\.?)/i.exec(fields);
const duration = /3\.4\.?\s*[^:]{0,100}:\s*([\s\S]*?)(?=3\.5\.?|4\s*[-–])/i.exec(fields);
if (place) result.teslimYeri = place[1].trim();
if (duration) result.teslimatSuresi = duration[1].trim();
if (/hizmet alımı\s+4734/i.test(content)) result.alimTuru = 'Kiralama ve Hizmet Alımı';
return result;
}