121 lines
4.2 KiB
JavaScript
121 lines
4.2 KiB
JavaScript
/**
|
||
* DT worker'ının doldurduğu SQLite'ı okuyup ihaleist tender modeline çevirir.
|
||
* Veritabanı yoksa (worker hiç koşmadıysa) sessizce boş liste döner.
|
||
*/
|
||
|
||
import fs from 'node:fs';
|
||
import { sektorBul } from './siniflandir.mjs';
|
||
import path from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
import { titleCaseTr } from './tr-text.mjs';
|
||
|
||
// node:sqlite bazı Node sürümlerinde deneysel/flag'li. Yoksa DT devre dışı kalır,
|
||
// ilan.gov.tr canlı verisi yine de çalışır.
|
||
let DatabaseSync = null;
|
||
try {
|
||
({ DatabaseSync } = await import('node:sqlite'));
|
||
} catch {
|
||
console.warn('[dt-store] node:sqlite yok — doğrudan temin devre dışı (açık ihaleler etkilenmez)');
|
||
}
|
||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||
const DB_PATH = path.join(__dirname, 'data', 'dt.sqlite');
|
||
|
||
function parseDetail(detailJson) {
|
||
if (!detailJson) return {};
|
||
try {
|
||
const d = JSON.parse(detailJson).dogrudanTeminDetayResult || {};
|
||
const dt = d.DogrudanTeminBilgileri || {};
|
||
const idare = d.IdareBilgileri || {};
|
||
const soz = d.SozlesmeBilgileri?.SozlesmeBilgisiList?.[0] || null;
|
||
return {
|
||
yasaMaddesi: dt.YasaKapsamiTeminMaddesi || null,
|
||
durum: dt.DtDurumu || null,
|
||
bransKodlari: dt.BransKodList || [],
|
||
kismiTeklif: dt.KismiTeklif || null,
|
||
idareTam: idare.Idare || null,
|
||
enUstIdare: idare.EnUstIdare || null,
|
||
kazananFirma: soz?.IstekliAdi || null,
|
||
sozlesmeBedeli: soz?.SozlesmeBedeli || null,
|
||
sozlesmeTarihi: soz?.SozlesmeTarihi || null,
|
||
};
|
||
} catch {
|
||
return {};
|
||
}
|
||
}
|
||
|
||
const KURUM_RULES = [
|
||
[/hastane|sağlık|başhekim|tıp merkezi|adsm|ağız ve diş/i, 'Sağlık Kurumları'],
|
||
[/ceza infaz|cezaevi|tutukevi|işyurt/i, 'Ceza İnfaz Kurumları'],
|
||
[/üniversite|rektörlü/i, 'Üniversiteler'],
|
||
[/büyükşehir belediye/i, 'Büyükşehir Belediyeleri'],
|
||
[/belediye/i, 'Belediyeler'],
|
||
[/bakanlığı|valiliği|müdürlüğü|komutanlığı/i, 'Bakanlık / Kamu Kurumları'],
|
||
];
|
||
|
||
function classifyKurum(text) {
|
||
for (const [re, label] of KURUM_RULES) if (re.test(text || '')) return label;
|
||
return 'Diğer Kamu Kurumları';
|
||
}
|
||
|
||
function mapDtRow(row) {
|
||
const det = parseDetail(row.detail_json);
|
||
const kurum = det.idareTam || row.idare_adi || '';
|
||
return {
|
||
id: `dt-${row.dogrudan_temin_id}`,
|
||
kaynak: 'EKAP · Doğrudan Temin',
|
||
kaynakUrl: 'https://ekap.kik.gov.tr/EKAP/YeniIhaleArama.aspx',
|
||
ikn: row.dtn || '',
|
||
baslik: row.isin_adi || '',
|
||
kurum,
|
||
sehir: row.ili && !row.ili.startsWith('Plaka') ? titleCaseTr(row.ili) : '',
|
||
bolge: '',
|
||
tarih: row.dt_tarihi || '',
|
||
saat: '',
|
||
alimTuru: 'Doğrudan Temin',
|
||
usul: det.yasaMaddesi ? `Doğrudan Temin (4734 ${det.yasaMaddesi})` : 'Doğrudan Temin (4734 22/d)',
|
||
// Sektör ihale TÜRÜ değildir; başlık + kalem adlarından çıkarılır.
|
||
sektor: sektorBul(row.isin_adi || '', (det.bransKodlari || []).join(' '), row.turu || ''),
|
||
brans: (det.bransKodlari || []).join(', ') || row.turu || 'Genel',
|
||
kurumTipi: classifyKurum(kurum),
|
||
eklenmeZamani: row.yayim_tarihi ? `Yayım: ${row.yayim_tarihi}` : '',
|
||
isYeni: false,
|
||
isLiveFeed: true,
|
||
aciliyetBadge: null,
|
||
items: [],
|
||
aciklama: null,
|
||
yaklasikMaliyet: null,
|
||
teslimatSuresi: null,
|
||
teslimYeri: null,
|
||
yeterlikKriterleri: [],
|
||
aiMatchScore: null,
|
||
aiRiskScore: null,
|
||
aiBidRange: null,
|
||
kanbanStatus: 'incelenecek',
|
||
atananPersonel: null,
|
||
durum: det.durum || 'Aktif',
|
||
incelendi: false,
|
||
takipte: false,
|
||
// Sonuçlanmış DT'lerde kazanan/fiyat bilgisi
|
||
sozlesmeBedeli: det.sozlesmeBedeli || null,
|
||
kazananFirma: det.kazananFirma || null,
|
||
};
|
||
}
|
||
|
||
export function readDtTenders(limit = 300) {
|
||
if (!DatabaseSync || !fs.existsSync(DB_PATH)) return { tenders: [], totalCount: 0, available: false };
|
||
const db = new DatabaseSync(DB_PATH, { readOnly: true });
|
||
try {
|
||
const total = db.prepare('SELECT COUNT(*) c FROM dt_tenders').get().c;
|
||
const rows = db
|
||
.prepare(
|
||
`SELECT dogrudan_temin_id, dtn, isin_adi, idare_adi, turu, ili, dt_tarihi, yayim_tarihi, detail_json
|
||
FROM dt_tenders ORDER BY rowid DESC LIMIT ?`,
|
||
)
|
||
.all(limit);
|
||
return { tenders: rows.map(mapDtRow), totalCount: total, available: true };
|
||
} finally {
|
||
db.close();
|
||
}
|
||
}
|