diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index c89ff21..912dc9b 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -307,3 +307,9 @@ Doğrulama: üretim derlemesi geçti; HTTP testi, başarısız çıkarım ve yen İhale detayındaki yükleme ve yeniden kalem çıkarımı, dosya metni okunamadığında sahiplik kontrollü read-error uç noktasına hata bildiriyor. Sunucu serbest hata metni veya başarı durumu kabul etmiyor; sabit, kullanıcıya yönelik okuma hatasını saklıyor. İstemcinin gördüğü önceki işleme durumu atomik UPDATE koşuluyla karşılaştırılıyor; gecikmiş hata bildirimi daha yeni sonucu ezemiyor (409). Bildirim kaydedilemezse arayüz bunu ayrıca belirtiyor. 70 test geçti. HTTP kapsamında oturumsuz/başka hesap/firma belgesi reddi, kalıcı hata ve eski durumla tekrar bildirimin 409 olması doğrulandı. Mevcut dosya ve baytları sonraki çıkarım denemelerinde korunuyor. Gerçek PDF ile tarayıcı kabulü ve genel depoya yeniden işleme entegrasyonu açık; bu değişiklik tam D01 kabulü sayılmıyor. + +### Genel belge deposunda yeniden işleme + +Doküman Deposu'nda İKN bağlantılı, okunabilir ihale belgelerine yeniden kalem çıkarımı eklendi. İhale detayı ve depo artık aynı storedDocument servisiyle mevcut dosyayı okuyor, okuma hatasını kaydediyor ve sahiplik kontrollü kalem aktarımı yapıyor. Özel firma belgeleri bu işleme dahil değil. İşlem sonucu ve liste yenileme hatası ayrı gösteriliyor. Belge okuma sırasında oturum değişirse eski belge metninin yeni oturumla aktarımı veya hata bildirimi durduruluyor. + +71 test geçti; üretim derlemesi geçti. Yeni servis testi mevcut dosya ID/İKN/metin aktarımını, okuma hatasının önceki durumla raporlanmasını ve hesap değişikliğinde ikinci isteğin gönderilmemesini doğruluyor. Gerçek tarayıcı PDF kabulü ve tüm depo işlemlerinin hesap değişiminde ekran durumlarını temizlemesi henüz açık. diff --git a/src/components/TenderDocuments.jsx b/src/components/TenderDocuments.jsx index 0872f21..e6b12b7 100644 --- a/src/components/TenderDocuments.jsx +++ b/src/components/TenderDocuments.jsx @@ -1,3 +1,4 @@ +import { readableDocument, readStoredDocument, retryDocumentExtraction } from '../services/storedDocument'; import { documentProcessingLabel } from '../services/documentProcessing'; import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useApp } from '../context/AppContext'; @@ -88,44 +89,13 @@ export const TenderDocuments = ({ tender }) => { try { await deleteDocument(id); belgeleriYukle(); } catch (err) { setError(err.message); } }; - // PDF/metin tarayıcıda (pdfjs) okunur; docx/xlsx/zip için tarayıcıda çözücü - // yok, sunucudaki çıkarıcıya sorulur. .doc ve .rar'ın karşılığı yok. - const tarayicidaOkunur = (ad) => /\.(pdf|txt|md)$/i.test(String(ad || '')); - const sunucudaOkunur = (ad) => /\.(docx|xlsx|zip)$/i.test(String(ad || '')); - const okunabilirMi = (ad) => tarayicidaOkunur(ad) || sunucudaOkunur(ad); - - const belgeMetni = async (b) => { - if (sunucudaOkunur(b.ad)) { - const r = await fetch(`/api/me/documents/text?id=${encodeURIComponent(b.id)}`, { - headers: { Authorization: `Bearer ${getToken()}` }, - }); - const d = await r.json().catch(() => ({})); - if (!d.success) throw new Error(d.error || 'metin çıkarılamadı'); - return d.metin; - } - const r = await fetch(`/api/me/documents/download?id=${encodeURIComponent(b.id)}`, { - headers: { Authorization: `Bearer ${getToken()}` }, - }); - if (!r.ok) throw new Error('belge indirilemedi'); - const blob = await r.blob(); - // extractText { text, pageCount, usedPages } döndürür — nesneyi metin sanıp - // göndermek analizi sessizce bozuyordu. - const { text } = await extractText(new File([blob], b.ad, { type: b.mime || 'application/pdf' })); - return text; - }; + const okunabilirMi = readableDocument; + const belgeMetni = readStoredDocument; const kalemleriYenidenCikar = async (b) => { setBusy('kalem'); setError(null); setBilgi(null); try { - let metin; - try { metin = await belgeMetni(b); } - catch (readError) { - try { await reportDocumentReadError(b.id,b.isleme); } - catch { throw new Error(`${readError.message} (hata durumu kaydedilemedi; listeyi yenileyin)`); } - throw readError; - } - const { kalemCikar } = await import('../services/kalem'); - const result = await kalemCikar({ ikn, metin, dosya:b.ad, documentId:b.id }); + const result = await retryDocumentExtraction(b); setBilgi({ isleme: `${b.ad}: ${result.sayi || 0} kalem çıkarıldı.` }); } catch (e) { setError(`Kalem çıkarımı tamamlanamadı: ${e.message}. Dosya kaydı korunmuştur.`); } finally { await belgeleriYukle(); setBusy(null); } diff --git a/src/components/tools/DocumentVault.jsx b/src/components/tools/DocumentVault.jsx index f9a78fd..c9616ab 100644 --- a/src/components/tools/DocumentVault.jsx +++ b/src/components/tools/DocumentVault.jsx @@ -1,3 +1,4 @@ +import { readableDocument, retryDocumentExtraction } from '../../services/storedDocument'; import { documentProcessingLabel } from '../../services/documentProcessing'; import React, { useState, useEffect, useRef } from 'react'; import { useApp } from '../../context/AppContext'; @@ -16,6 +17,7 @@ export const DocumentVault = () => { const [durum, setDurum] = useState(null); const [busy, setBusy] = useState(false); const [hata, setHata] = useState(null); + const [islemeBilgi, setIslemeBilgi] = useState(null); const [kategori, setKategori] = useState(KATEGORILER[0]); const dosyaRef = useRef(null); @@ -26,6 +28,19 @@ export const DocumentVault = () => { }; useEffect(yukle, [authUser]); + const yenidenIsle = async (document) => { + setBusy(true); setHata(null); setIslemeBilgi(null); + try { + const result = await retryDocumentExtraction(document); + setIslemeBilgi(`${document.ad}: ${result.sayi || 0} kalem çıkarıldı.`); + } catch (error) { setHata(error.message); } + finally { + try { setDurum(await listDocuments()); } + catch { setHata(previous => [previous, 'Belge listesi yenilenemedi.'].filter(Boolean).join(' ')); } + setBusy(false); + } + }; + const dosyaSecildi = async (e) => { const f = e.target.files?.[0]; if (!f) return; @@ -250,6 +265,7 @@ export const DocumentVault = () => { ) : (
{islemeBilgi}
} {durum.belgeler.map((d) => (