feat: version tender calendar events
This commit is contained in:
@@ -1264,3 +1264,9 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö
|
||||
- Eksiklere geçiş düğmeleri aynı veri ve olay işleyicilerini kullanıyor. Tablo/satır/hücre rolleri ve sütun başlıkları korunuyor; mobil görsel alan etiketleri ekran okuyucu için tekrar edilmiyor. Uzun kesintisiz metinler satıra bölünebiliyor.
|
||||
- Build ve diff kontrolü başarılı. 390/768/1440 piksel tarayıcı görsel kabulü, klavye ve gerçek ekran okuyucu doğrulaması henüz yapılmadı. Bu düzenleme tüm mobil kabulün geçtiği anlamına gelmez. Genel plan açık.
|
||||
- QA düzeneğine aynı özetin 390/768/1440 içerik genişliğiyle açılabildiği bir görünüm yolu eklendi ve uzun başlık/atanan sorumlu verisiyle hedef bağlantısı ölçüldü. Uygulama içi tarayıcı sekmesinin görünüm alanı yeniden boyutlandırılamadığı için bu ölçüm gerçek mobil viewport kabulü sayılmadı; mobil doğrulama hâlâ açık.
|
||||
|
||||
### 2026-09-06 — ICS kaynak sürümü
|
||||
|
||||
- D02 kapsamında ICS olayına `SEQUENCE` eklendi. Değer, doğrulanmış `icsSequence` veya doküman sürümünden güvenli bir negatif olmayan tamsayı olarak alınır; geçersiz değerler sıfıra düşer. İKN tabanlı UID sabit kalır, tarih değişiminde istemcilerin aynı etkinliği güncellemesi mümkün olur.
|
||||
- Açıklamadaki “otomatik güncellenmez” ifadesi, kaynak sürümü ve resmi doğrulama gereğini belirten güncelleme yönlendirmesiyle değiştirildi. ICS’nin kendisi hâlâ resmi takvim servisine otomatik gönderim yapmaz.
|
||||
- Regresyon testi UID sürekliliğini ve 3→4 sürüm artışını doğruluyor. 278 test ve build başarılı. Google/Outlook gerçek test takvimlerine aktarım henüz yapılmadı; genel plan açık.
|
||||
|
||||
@@ -29,11 +29,13 @@ export function createTenderICS(t, now = new Date()) {
|
||||
const start = tenderDeadline(t);
|
||||
const uid = encodeURIComponent(String(t.ikn || t.id || '').trim());
|
||||
if (!uid) throw new Error('İhale kimliği gerekli.');
|
||||
const rawSequence=Number(t.icsSequence ?? t.documentVersion ?? 0);
|
||||
const sequence=Number.isSafeInteger(rawSequence)&&rawSequence>=0 ? rawSequence : 0;
|
||||
return ['BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//Ihaleist//Tender Calendar//TR','CALSCALE:GREGORIAN',
|
||||
'BEGIN:VEVENT',`UID:${uid}@ihaleist.com`,`DTSTAMP:${stamp(now)}`,
|
||||
`DTSTART:${stamp(start)}`,'TRANSP:TRANSPARENT',
|
||||
`SEQUENCE:${sequence}`,`DTSTART:${stamp(start)}`,'TRANSP:TRANSPARENT',
|
||||
`SUMMARY:${escapeICS('İhale son teklif: '+t.baslik)}`,
|
||||
`DESCRIPTION:${escapeICS('İKN: '+t.ikn+' — '+t.kurum+'\nBu tek seferlik takvim kaydı otomatik güncellenmez. İhale tarihini resmi kaynaktan doğrulayın; değişiklikte takviminizdeki eski kaydı güncelleyin.')}`,
|
||||
`DESCRIPTION:${escapeICS('İKN: '+t.ikn+' — '+t.kurum+'\nKaynak sürümünü ve ihale tarihini resmi kaynaktan doğrulayın; zeyilname veya tarih değişikliğinde aynı UID ve artan sürümle takvimi güncelleyin.')}`,
|
||||
'END:VEVENT','END:VCALENDAR',''].map(fold).join('\r\n');
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,18 @@ test('deadline ICS is a transparent instant, preserves UID across date changes a
|
||||
assert.match(changed,/DTSTART:20260912T113000Z/);
|
||||
assert.doesNotMatch(changed,/DTEND:|DURATION:/);
|
||||
assert.match(changed,/TRANSP:TRANSPARENT/);
|
||||
assert.match(changed.replace(/\r\n /g,''),/otomatik güncellenmez/);
|
||||
assert.match(changed.replace(/\r\n /g,''),/artan sürümle takvimi güncelle/);
|
||||
const hostile=createTenderICS({...t,baslik:'A\rEND:VEVENT\rBEGIN:VEVENT\nB'});
|
||||
assert.equal(hostile.split('\r\n').filter(line=>line==='BEGIN:VEVENT').length,1);
|
||||
assert.equal(hostile.split('\r\n').filter(line=>line==='END:VEVENT').length,1);
|
||||
});
|
||||
test('ICS exposes a stable event version for calendar updates',()=>{
|
||||
const first=createTenderICS({...t,documentVersion:3},new Date('2026-09-01T00:00:00Z'));
|
||||
const changed=createTenderICS({...t,tarih:'12.09.2026',saat:'14:30',documentVersion:4},new Date('2026-09-02T00:00:00Z'));
|
||||
assert.match(first,/SEQUENCE:3/); assert.match(changed,/SEQUENCE:4/);
|
||||
assert.equal(first.match(/UID:[^\r\n]+/)[0],changed.match(/UID:[^\r\n]+/)[0]);
|
||||
assert.match(changed,/art%C4%B1?an|artan sürüm|artan/);
|
||||
});
|
||||
|
||||
test('calendar agenda sorts known times before unknown and preserves undated records',async()=>{
|
||||
const {calendarAgenda}=await import('../src/services/tenderCalendar.js');
|
||||
|
||||
Reference in New Issue
Block a user