fix: preserve bid drafts and align tender source data

This commit is contained in:
2026-09-06 08:40:10 +03:00
parent c91631d99f
commit 456728b4bd
26 changed files with 510 additions and 81 deletions
+37
View File
@@ -0,0 +1,37 @@
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) {
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};
const deadline = /Tarih\s*ve\s*Saati\s*:\s*(\d{2}\.\d{2}\.\d{4})\s*[-–]?\s*(\d{2}:\d{2})/i.exec(content);
if (deadline) { result.tarih = deadline[1]; result.saat = deadline[2]; }
const place = /3\.3\.?\s*[^:]{0,120}:\s*([\s\S]*?)(?=3\.4\.?)/i.exec(content);
const duration = /3\.4\.?\s*[^:]{0,100}:\s*([\s\S]*?)(?=3\.5\.?|4\s*[-–])/i.exec(content);
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;
}