87 lines
4.9 KiB
JavaScript
87 lines
4.9 KiB
JavaScript
// Haftalık brief — Pazartesi 08:00: takipteki ihalelerden bu hafta yapılacaklar,
|
||
// önceki yedi takvim günündeki takipli sonuç kayıtları.
|
||
// Telegram (bağlıysa) + e-posta; kalıcı mesaj kabul kayıtları brief.sqlite.
|
||
// Eski brief-son.json yalnız geçiş haftasında tekrar göndermemek için okunur.
|
||
import fs from 'node:fs';
|
||
import { createBriefOutbox } from './brief-outbox.mjs';
|
||
import { createBriefBuilder } from './brief-content.mjs';
|
||
import { createBriefSender } from './brief-delivery.mjs';
|
||
import path from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
import * as store from './user-store.mjs';
|
||
import { resultsByIkn } from './history-store.mjs';
|
||
import { emailConfigured, sendEmail } from './email.mjs';
|
||
import { sendTelegram, telegramConfigured } from './telegram.mjs';
|
||
import { yaklasanIhaleler, trTarih } from './feeds-mcp.mjs';
|
||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||
const DURUM_DOSYASI = path.join(__dirname, 'data', 'brief-son.json');
|
||
|
||
function sonGonderim() {
|
||
try { return JSON.parse(fs.readFileSync(DURUM_DOSYASI, 'utf8')); } catch { return {}; }
|
||
}
|
||
|
||
const paraTR = (v, birim) => (v == null ? '' : `${Number(v).toLocaleString('tr-TR')} ${birim || 'TL'}`);
|
||
|
||
/** Bir kullanıcı için brief içeriği. */
|
||
export const briefOlustur = createBriefBuilder({
|
||
trackedKeys:store.getTrackedTenderKeys, upcoming:yaklasanIhaleler, results:resultsByIkn, parseDate:trTarih,
|
||
});
|
||
|
||
const deadlineText = t => t.son_teklif_zamani
|
||
? new Date(t.son_teklif_zamani).toLocaleTimeString('tr-TR', { timeZone: 'Europe/Istanbul', hour: '2-digit', minute: '2-digit' }) + ' (Türkiye saati)'
|
||
: 'saat doğrulanmalı';
|
||
|
||
export function briefMetni(b) {
|
||
const s = [`📋 Haftalık İhale Brief — ${b.hafta}`];
|
||
if (b.yaklasan.length) {
|
||
s.push('', `⏰ Bu hafta yapılacak takipli ihaleler (${b.yaklasan.length}):`);
|
||
for (const t of b.yaklasan) s.push(`• ${t.kalan_gun === 0 ? 'BUGÜN' : t.kalan_gun + ' gün'} — ${t.baslik} (${t.kurum}, ${t.tarih} · ${deadlineText(t)})`);
|
||
}
|
||
if (b.sonuclar.length) {
|
||
s.push('', `🏁 Önceki 7 takvim günündeki takipli sonuç kayıtları (${b.sonuclar.length}):`);
|
||
for (const r of b.sonuclar) s.push(`• ${r.baslik} → ${r.kazanan || 'kazanan açıklanmadı'}${r.bedel != null ? ' · ' + paraTR(r.bedel, r.birim) : ''}${r.teklif != null ? ' · ' + r.teklif + ' teklif' : ''}`);
|
||
}
|
||
s.push('', 'ihaleist.com');
|
||
return s.join('\n');
|
||
}
|
||
|
||
export function briefHtml(b) {
|
||
const esc = (x) => String(x ?? '').replace(/[<>&]/g, (c) => ({ '<': '<', '>': '>', '&': '&' }[c]));
|
||
const bolum = (baslik, satirlar) => satirlar.length
|
||
? `<h3 style="margin:18px 0 6px;font-size:15px;color:#0f172a">${baslik}</h3><ul style="margin:0;padding-left:18px;color:#334155;font-size:14px">${satirlar.map((x) => `<li style="margin:4px 0">${x}</li>`).join('')}</ul>` : '';
|
||
return `<div style="font-family:Inter,Arial,sans-serif;max-width:640px;margin:auto;padding:20px;color:#0f172a">
|
||
<h2 style="margin:0 0 4px;font-size:20px">📋 Haftalık İhale Brief</h2><div style="color:#64748b;font-size:13px">${esc(b.hafta)}</div>
|
||
${bolum('⏰ Bu hafta yapılacak takipli ihaleler', b.yaklasan.map((t) => `<b>${t.kalan_gun === 0 ? 'BUGÜN' : t.kalan_gun + ' gün'}</b> — ${esc(t.baslik)} (${esc(t.kurum)}, ${esc(t.tarih)} · ${esc(deadlineText(t))})`))}
|
||
${bolum('🏁 Önceki 7 takvim günündeki takipli sonuç kayıtları', b.sonuclar.map((r) => `${esc(r.baslik)} → ${esc(r.kazanan || 'kazanan açıklanmadı')}${r.bedel != null ? ' · ' + esc(paraTR(r.bedel, r.birim)) : ''}`))}
|
||
<p style="margin-top:20px;font-size:12px;color:#94a3b8">Bu brief her Pazartesi gönderilir; Bildirimler sekmesinden kapatabilirsiniz.</p></div>`;
|
||
}
|
||
|
||
export const haftalikBriefGonder = createBriefSender({
|
||
store, buildBrief:briefOlustur, text:briefMetni, html:briefHtml,
|
||
telegramConfigured, sendTelegram, emailConfigured, sendEmail,
|
||
outbox:createBriefOutbox(process.env.IHALEIST_USER_DATA_DIR || path.join(__dirname,'data')),
|
||
});
|
||
|
||
export function briefScheduleKey(now = new Date()) {
|
||
const tr = new Date(now.getTime() + 3 * 3600000);
|
||
if (tr.getUTCDay() !== 1 || tr.getUTCHours() < 8) return null;
|
||
return `${tr.getUTCFullYear()}-${tr.getUTCMonth()}-${tr.getUTCDate()}`;
|
||
}
|
||
|
||
/** Saatlik kontrol: Türkiye saatiyle Pazartesi ≥08:00. */
|
||
export function briefZamanlayici(tenderGetir) {
|
||
if (process.env.BRIEF_ENABLED === '0') { console.log('[brief] haftalık brief devre dışı (BRIEF_ENABLED=0)'); return; }
|
||
const kontrol = async () => {
|
||
const anahtar = briefScheduleKey();
|
||
if (!anahtar) return;
|
||
const d = sonGonderim();
|
||
if (d.son === anahtar) return;
|
||
const r = await haftalikBriefGonder(tenderGetir).catch((e) => ({ hata: e.message }));
|
||
console.log('[brief] haftalık brief:', JSON.stringify(r));
|
||
};
|
||
setTimeout(kontrol, 3 * 60 * 1000).unref?.();
|
||
setInterval(kontrol, 60 * 60 * 1000).unref?.();
|
||
console.log('[brief] haftalık brief zamanlandı (Pazartesi 08:00, saatlik kontrol)');
|
||
}
|