Files
ihaleist/server/dt-store.mjs
T
hikmettan 89cfd03d92 feat: canlı veri — ilan.gov.tr açık ihale + EKAP doğrudan temin (22/d)
- server/index.js: ilan.gov.tr proxy (açık ihale + kira/satış), TLS zincir düzeltmesi
- server/dt-worker.mjs: EKAP doğrudan temin toplayıcı (Playwright, imzasız oturum içi fetch)
- server/dt-store.mjs + il-plaka.mjs: DT verisini tender modeline çevirme
- src/services/tenderApi.js + AppContext: mock veri yerine canlı API
- Doğrudan Temin sekmesi 256 gerçek 22/d kaydıyla dolu
2026-08-26 20:45:02 +03:00

110 lines
3.7 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.
/**
* 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 { DatabaseSync } from 'node:sqlite';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
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') ? 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)',
sektor: row.turu || 'Genel',
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 (!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();
}
}