fix: align server deadlines and follow consumers with preparation state

This commit is contained in:
2026-09-06 09:09:10 +03:00
parent 7ad5fb4f50
commit 144724484c
8 changed files with 124 additions and 33 deletions
+16 -7
View File
@@ -25,7 +25,7 @@ const paraTR = (v, birim) => (v == null ? '' : `${Number(v).toLocaleString('tr-T
/** Bir kullanıcı için brief içeriği. */
export function briefOlustur(email, tenders) {
const takip = (store.getData(email, 'takip') || []).map(String);
const takip = store.getTrackedTenderKeys(email);
const yaklasan = yaklasanIhaleler(email, tenders, 7);
const birHafta = Date.now() - 7 * 86400000;
const sonuclar = [];
@@ -40,11 +40,15 @@ export function briefOlustur(email, tenders) {
return { hafta, yaklasan, sonuclar: sonuclar.slice(0, 15), bos: !yaklasan.length && !sonuclar.length };
}
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}${t.saat ? ' ' + t.saat : ''})`);
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('', `🏁 Geçen hafta sonuçlanan takipliler (${b.sonuclar.length}):`);
@@ -60,7 +64,7 @@ export function briefHtml(b) {
? `<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)})`))}
${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('🏁 Geçen hafta sonuçlanan takipliler', 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>`;
}
@@ -88,13 +92,18 @@ export async function haftalikBriefGonder(tenderGetir, { zorla = false } = {}) {
return r;
}
/** Saatlik kontrol: Pazartesi ≥08:00 ve bu hafta gönderilmediyse gönder. */
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 simdi = new Date();
if (simdi.getDay() !== 1 || simdi.getHours() < 8) return;
const anahtar = `${simdi.getFullYear()}-${simdi.getMonth()}-${simdi.getDate()}`;
const anahtar = briefScheduleKey();
if (!anahtar) return;
const d = sonGonderim();
if (d.son === anahtar) return;
sonGonderimYaz({ son: anahtar });