From b49ae4c59febef6020a93b9bc7268c333136fc27 Mon Sep 17 00:00:00 2001 From: ht Date: Sun, 6 Sep 2026 16:23:14 +0300 Subject: [PATCH] fix: handle malformed document lists in preparation overview --- docs/quality/uygulama-durumu.md | 5 +++++ src/components/PreparationOverview.jsx | 2 +- src/services/preparationSummary.js | 2 +- tests/preparation-summary.test.mjs | 5 +++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index b191338..fdea85e 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -1276,3 +1276,8 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö - Kayıtlı filtre oluşturma formu artık mevcut anahtar kelime, kurum adı, İKN, şehir, bölge, alım türü, kurum tipi ve ilk sektör ölçütünü başlangıç değeri olarak gösteriyor. Kullanıcı aynı aramayı tekrar elle kurmadan ad verip kaydedebiliyor. - Alanlar yalnız ilk oluşturulma anında okunuyor; form içindeki taslak değişiklikleri canlı liste durumunun etkisiyle ezilmiyor. Eski kayıt uygulama davranışı değişmedi. - 278 test ve build başarılı. Bu ön doldurma için ayrı tarayıcı kabulü henüz eklenmedi; genel plan açık. + +### 2026-09-06 — Belge deposu yanıt şekli dayanıklılığı + +- Hazırlık özeti, belge deposu yanıtında `belgeler` alanı eksik veya dizi dışı geldiğinde artık çökmüyor; boş belge listesiyle eksik kontrolü gösteriyor. Bileşen ve özet servisi aynı dizi doğrulamasını kullanıyor. +- Bozuk yanıt için regresyon testi eklendi. 279 test, build ve diff kontrolü başarılı. Gerçek ağ kesintisi kabulü daha önceki hata yolu ile sınırlı; genel plan açık. diff --git a/src/components/PreparationOverview.jsx b/src/components/PreparationOverview.jsx index e64c133..77ae12a 100644 --- a/src/components/PreparationOverview.jsx +++ b/src/components/PreparationOverview.jsx @@ -14,7 +14,7 @@ function Overview({tenders,now}) { useEffect(()=>{ let cancelled=false; setVault({loading:true,error:null,documents:[]}); - listDocuments().then(data=>{if(!cancelled)setVault({loading:false,error:null,documents:data.belgeler});}) + listDocuments().then(data=>{if(!cancelled)setVault({loading:false,error:null,documents:Array.isArray(data?.belgeler) ? data.belgeler : []});}) .catch(error=>{if(!cancelled)setVault({loading:false,error:error.message,documents:[]});}); return()=>{cancelled=true;}; },[refresh]); diff --git a/src/services/preparationSummary.js b/src/services/preparationSummary.js index 93ac432..f5f7e1e 100644 --- a/src/services/preparationSummary.js +++ b/src/services/preparationSummary.js @@ -34,7 +34,7 @@ export function preparationSummary(tender,vault,now=new Date()) { if(priced.length&&!validateBidRows(priced).length&&bidTotal(priced)===null)add('pricing','Genel toplam geçersiz veya hesaplama sınırını aşıyor.'); } if(bidType==='goturu'&&bidAmount(draft.goturuBedel)===null)add('lumpSum','Toplam teklif bedelini kontrol edin.'); - const checkedVault={...vault,deadlineDate:tenderDateKey(tender),tenderIkn:tender.ikn}; + const checkedVault={...vault,documents:Array.isArray(vault?.documents) ? vault.documents : [],deadlineDate:tenderDateKey(tender),tenderIkn:tender.ikn}; const documentIssues=preparationBlockers([],documents,draft.checks,checkedVault); preparationBlockers(selection.rows,documents,draft.checks,checkedVault).forEach(text=>add('checks',text)); return {issues,documentIssues,owner:tender.atananPersonel || 'Atanmadı',next:issues[0] || {target:'source',text:'Dosyayı açıp son kontrolleri yapın.'}}; diff --git a/tests/preparation-summary.test.mjs b/tests/preparation-summary.test.mjs index 9840584..48e1c1c 100644 --- a/tests/preparation-summary.test.mjs +++ b/tests/preparation-summary.test.mjs @@ -30,3 +30,8 @@ test('expired source takes priority over completion or manually moved Kanban sta assert.equal(summary.next.target,'source'); assert.equal(summary.owner,'Atanmadı'); }); +test('malformed document response is treated as empty instead of crashing the summary',()=>{ + assert.doesNotThrow(()=>preparationSummary(tender,{loading:false,error:null,documents:null},now)); + const summary=preparationSummary(tender,{loading:false,error:null,documents:null},now); + assert.ok(summary.documentIssues.some(text=>text.includes('belge'))); +});