diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index d71a4f3..681620f 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -34,9 +34,17 @@ Tarayıcı kanıtı: [Yenileme sonrası beş kart](evidence/qa-kanban-after-relo - Eski konumsal fiyatlar kaynak satırları olmadan güvenle eşlenemediği için otomatik taşınmaz; kullanıcıya yeniden giriş gerektiği gösterilir. Bu davranış yeni taslak kaydında da korunur. - Üç regresyon testi sıralama, içerik değişikliği ve eski taslak senaryolarını doğrular. Henüz gerçek belge yükleme/zeyilname ve tarayıcı form kabulü tamamlanmadı. Bu kontrol tüm belge/AI kaynak sürüm modelinin yerine geçmez. +## Belge ve sağlık ürünü kontrolleri + +- Hazırlık formunda kaynak maddeli belge gereksinimi ekleme/kaldırma, belge adı/sürümü ve geçerlilik kontrolü kaydı eklendi. Zorunlu belgeye uygulanmıyor denilerek çıktı engeli aşılamaz. +- Kalem bazında ürün/model veya hizmet kapsamı, teknik uygunluk kaynağı, sorumlu, ÜTS, numune/demonstrasyon, servis/kurulum ve teslimat kontrolleri bulunur. Uygulanmıyor seçimi gerekçe ister; uygun olmayan ürün çıktıyı engeller. +- Eksik kontrollerin listesi fiyatlandırma ekranında görünür. Bu alanlar kullanıcı beyanı/kontrol kaydıdır; belge deposundaki gerçek dosyaya otomatik bağlantı ve resmi yeterlik doğrulaması henüz yoktur. +- Kontroller, elle eklenen belgeler ve analizden gelen kalem/belge listesi taslakla saklanır. HTTP testi bu alanların hesap içinde yazılıp geri okunmasını doğrular. Üç kural testi eksik kaynak, uygun olmayan ürün, zorunlu belgenin atlanması ve değişmiş gereksinimleri kapsar. +- Tarayıcıda tüm bu alanları doldurma, yenileme ve çok kalemli kullanılabilirlik kabulü bekliyor. AI raporundaki eski yerel checklist işaretleri henüz bu kalıcı kontrol modeline bağlanmadı. D06/D07 tamamlanmış sayılmaz. + ## Doğrulama -`npm test`: 22/22 geçti (son yeniden çalıştırma: 6 Eylül 2026). +`npm test`: 25/25 geçti (son yeniden çalıştırma: 6 Eylül 2026). `npm run build`: geçti; mevcut büyük paket/dinamik import uyarıları sürüyor. `node --check server/index.js`, `node --check server/user-store.mjs`, `git diff --check`: geçti. diff --git a/src/components/BidPackageBuilder.jsx b/src/components/BidPackageBuilder.jsx index 0e1a5f9..794a774 100644 --- a/src/components/BidPackageBuilder.jsx +++ b/src/components/BidPackageBuilder.jsx @@ -1,6 +1,8 @@ import React, { useState, useMemo } from 'react'; import { bidRowTotal, validateBidRows, roundMoney } from '../services/bidValidation'; import { sourceRows, bidSourceSnapshot, restoreBidPrices } from '../services/bidSource'; +import { PreparationChecks } from './PreparationChecks'; +import { preparationBlockers, documentKey } from '../services/preparationChecks'; import { useApp } from '../context/AppContext'; import { FolderCheck, ChevronDown, ChevronUp, FileSignature, Table2, ListChecks, @@ -59,8 +61,12 @@ export const BidPackageBuilder = ({ results, tender }) => { const [kisim, setKisim] = useState(storedDraft.kisim || ''); const [goturuBedel, setGoturuBedel] = useState(storedDraft.goturuBedel || ''); - const kalemler = sourceRows(tender, results); - const sourceSnapshot = bidSourceSnapshot(tender, results, kalemler); + const effectiveResults = results || storedDraft.analysisSource || {}; + const [manualDocuments, setManualDocuments] = useState(storedDraft.manualDocuments || []); + const [checks, setChecks] = useState(storedDraft.checks || {}); + const documents = [...new Map([...(effectiveResults.documentChecklist || []), ...manualDocuments].map(d => [documentKey(d),d])).values()]; + const kalemler = sourceRows(tender, effectiveResults); + const sourceSnapshot = bidSourceSnapshot(tender, {...effectiveResults, documentChecklist:documents}, kalemler); const [reviewedSource, setReviewedSource] = useState(storedDraft.reviewedSource || null); const [fiyatlar, setFiyatlar] = useState(() => restoreBidPrices(storedDraft)); const kaynakKontrolGerekli = reviewedSource !== sourceSnapshot; @@ -79,7 +85,7 @@ export const BidPackageBuilder = ({ results, tender }) => { const kalemToplami = useMemo(() => roundMoney(satirlar.reduce((t,r) => t + (bidRowTotal(r) ?? 0),0)), [satirlar]); const saveDraft = async () => { - const saved = await mutateTender(tender.id, {bidDraft:{firma,teklifTuru,gecerlilikGun,kisim,goturuBedel,priceSchema:1,pricesBySource:fiyatlar,sourceSnapshot,reviewedSource}}); + const saved = await mutateTender(tender.id, {bidDraft:{firma,teklifTuru,gecerlilikGun,kisim,goturuBedel,priceSchema:1,pricesBySource:fiyatlar,sourceSnapshot,reviewedSource,checks,manualDocuments,analysisSource:{itemsAndSpecs:effectiveResults.itemsAndSpecs || [],documentChecklist:effectiveResults.documentChecklist || [],documentVersion:effectiveResults.documentVersion || null}}}); if (saved) { setDirty(false); setHata(null); } else setHata('Taslak kaydedilemedi. Tekrar deneyin.'); }; @@ -90,7 +96,8 @@ export const BidPackageBuilder = ({ results, tender }) => { const kalemEksik = teklifTuru === 'birim' && validateBidRows(satirlar).length > 0; const turCeliskisi = teklifTuru === 'goturu' && /birim fiyat/i.test(tender?.aciklama || ''); const sureEksik = !(Number(gecerlilikGun) > 0) || (kaynakGecerlilik && Number(gecerlilikGun) < Number(kaynakGecerlilik[1])); - const hazir = eksikler.length === 0 && toplam > 0 && !kalemEksik && !turCeliskisi && !sureEksik && !kaynakKontrolGerekli; + const kontrolEksikleri = preparationBlockers(kalemler, documents, checks); + const hazir = eksikler.length === 0 && toplam > 0 && !kalemEksik && !turCeliskisi && !sureEksik && !kaynakKontrolGerekli && kontrolEksikleri.length === 0; const formVerisi = () => ({ ...firma, @@ -110,7 +117,7 @@ export const BidPackageBuilder = ({ results, tender }) => { const f = formVerisi(); if (tip === 'mektup') belgeYazdir('Teklif Mektubu', teklifMektubuHtml(f, toplam)); if (tip === 'cetvel') belgeYazdir('Birim Fiyat Teklif Cetveli', teklifCetveliHtml(f, satirlar, toplam)); - if (tip === 'liste') belgeYazdir('Evrak Kontrol Listesi', evrakListesiHtml(f, results?.documentChecklist || [])); + if (tip === 'liste') belgeYazdir('Evrak Kontrol Listesi', evrakListesiHtml(f, documents)); } catch (e) { setHata(e.message); } @@ -297,6 +304,13 @@ export const BidPackageBuilder = ({ results, tender }) => {
)} +Her kontrol için belge adı/sürümü ve kaynak maddeyi yazın. ÜTS, numune ve servis koşulları her ihalede zorunlu değildir; uygulanmıyorsa gerekçesini belirtin. Bu kayıtlar kullanıcı kontrolüdür; resmi uygunluk onayı değildir.
+Resmi dokümandan eksik belge gereksinimi ekle
+ + + +