{R_KAYNAK}. Birden fazla hizmet konusu varsa YM içinde ağırlıklı olana göre.
+
+ )}
+
+ {tur === 'yapim' && (
+
+ Sınır değer katsayısı N (md. 45.1.1.1)
+
+
+ )}
+
+
+
+
+
+ {!sonuc && (
+
+ Yaklaşık maliyeti ve teklifleri girin; sınır değer ve adımları burada görünür.
+
+ )}
+ {sonuc?.hata && (
+
{sonuc.hata}
+ )}
+ {sonuc && !sonuc.hata && (
+ <>
+
+
Aşırı düşük teklif sınır değeri
+
{tl(sonuc.sd)}
+ {altinda != null && (
+
+ {altinda ? : }
+
+ Teklifiniz {tl(benim)} — sınırın {altinda ? <>altında: aşırı düşük teklif açıklaması istenir (md. 79.2 / 45.1.2), maliyet bileşenlerini belgeyle savunmaya hazır olun.> : <>üstünde: aşırı düşük sorgusuna girmez.>}
+
+
+ )}
+
+
+
Hesap adımları
+
+ {sonuc.adimlar.map((a, i) =>
{a}
)}
+
+ {sonuc.haric?.length > 0 && (
+
Hesap dışı bırakılan teklifler: {sonuc.haric.map((x) => x.toLocaleString('tr-TR')).join(', ')}
+ )}
+
+ >
+ )}
+
+
+
+ Formüller Kamu İhale Genel Tebliği md. 79.1.1–79.1.2 (hizmet), 62/A.1 (mal) ve 45.1.1 (yapım) metninden alındı; yapım hesabı Tebliğ'in 45.2 örneğiyle (YM 100.000, N 1,20 → 52.281,00 TL) birebir doğrulandı.
+ Nihai sınır değeri ihale komisyonu tespit eder; bu hesap teklif stratejisi içindir.
+
+
+
+
+
+ );
+};
diff --git a/src/services/sinirDeger.js b/src/services/sinirDeger.js
new file mode 100644
index 0000000..4d54beb
--- /dev/null
+++ b/src/services/sinirDeger.js
@@ -0,0 +1,105 @@
+/**
+ * Aşırı düşük teklif sınır değeri — Kamu İhale Genel Tebliği'nden.
+ *
+ * KAYNAK (mevzuat.gov.tr, 9.5.13354, 2026-09-04'te okundu):
+ * - Md. 79.1.1 Personel çalıştırılmasına dayalı hizmet: SD = kâr hariç yaklaşık maliyet.
+ * - Md. 79.1.2 Dayalı olmayan hizmet: SD = ((YM + T1 + … + Tn) / (n + 1)) × R
+ * n: geçerli teklifler içinde YM'nin %60'ından düşük ve YM'den
+ * yüksek olanlar DIŞINDAKİ teklif sayısı. (Formül Tebliğ'de
+ * görsel; ekran görüntüsünden okundu.)
+ * - Md. 79.1.3 R her yıl 1 Şubat'tan geçerli Kurum'ca ilan edilir.
+ * - Md. 62/A.1 (Değişik RG 9/4/2026) Mal alımında aşırı düşük değerlendirmesi
+ * 79 uncu maddeye göre yapılır → mal alımı da bu formülü kullanır.
+ * - Md. 45.1.1 Yapım: YM'nin %120 üstü ve %40 altı hariç geçerli tekliflerin
+ * Tort1 ve σ'sı; [Tort1−σ, Tort1+σ] içindekilerin Tort2'si;
+ * C = Tort2/YM; K: C<0,60 → K=C; 0,60≤C≤1,00 → (3,2C−C²−0,6)/(C+1);
+ * C>1,00 → (C²−0,8C+1,4)/(C+1); SD = K×Tort2/(C×N).
+ * N (45.1.1.1): B/C/D/E grubu yapım işleri 1,00; diğer 1,20.
+ * Yuvarlama (45.2 örneği): Tort1, σ, Tort2 2 ondalık; C, K 3 ondalık.
+ *
+ * R KATSAYILARI 2026 (KİK Kurul kararı 21.01.2026, ilanı 1/2/2026+ ihaleler):
+ */
+export const R_2026 = [
+ { ad: 'Araç Kiralama Hizmetleri', r: 0.77 },
+ { ad: 'Bilgisayar Sistemlerine Yönelik Hizmetler', r: 0.87 },
+ { ad: 'Malzemeli Yemek Hizmetleri', r: 0.77 },
+ { ad: 'Mühendislik Hizmetleri', r: 0.72 },
+ { ad: 'Sigorta Hizmetleri', r: 0.74 },
+ { ad: 'Personel/Öğrenci Taşıma Hizmetleri', r: 0.78 },
+ { ad: 'Diğer Hizmetler', r: 0.78 },
+];
+export const R_KAYNAK = 'KİK Kurul Kararı 21.01.2026 — ilanı 1/2/2026 ve sonrası ihaleler';
+
+const yuvarla = (x, b) => Math.round((x + Number.EPSILON) * 10 ** b) / 10 ** b;
+const sayi = (v) => {
+ if (typeof v === 'number') return v;
+ const s = String(v ?? '').trim().replace(/\s|TL|₺/gi, '');
+ if (!s) return NaN;
+ // "1.500.000,50" (TR) ya da "1500000.50"
+ const tr = s.includes(',') ? s.replace(/\./g, '').replace(',', '.') : s.replace(/\.(?=\d{3}(\D|$))/g, '');
+ return Number(tr);
+};
+export const teklifleriAyir = (metin) =>
+ String(metin || '').split(/[\n;]+/).map((x) => sayi(x)).filter((x) => Number.isFinite(x) && x > 0);
+
+/** Hizmet (personel dayalı olmayan) ve mal alımı — Md. 79.1.2 */
+export function sinirDegerHizmet({ ym, teklifler, r }) {
+ const YM = sayi(ym); const R = Number(r);
+ if (!(YM > 0) || !(R > 0)) return { hata: 'Yaklaşık maliyet ve R katsayısı gerekli' };
+ const gecerli = teklifler.filter((t) => t >= YM * 0.6 && t <= YM);
+ const disi = teklifler.filter((t) => t < YM * 0.6 || t > YM);
+ const n = gecerli.length;
+ const toplam = gecerli.reduce((a, b) => a + b, 0);
+ const ort = (YM + toplam) / (n + 1);
+ const sd = yuvarla(ort * R, 2);
+ return {
+ tur: 'hizmet', sd, n, r: R, ym: YM,
+ hesapOrtalama: yuvarla(ort, 2), dahil: gecerli, haric: disi,
+ adimlar: [
+ `Geçerli teklifler içinde YM'nin %60'ından düşük (${yuvarla(YM * 0.6, 2).toLocaleString('tr-TR')}) ve YM'den yüksek olanlar çıkarıldı: ${disi.length} teklif hariç, n = ${n}`,
+ `(YM + ΣT) / (n + 1) = (${YM.toLocaleString('tr-TR')} + ${toplam.toLocaleString('tr-TR')}) / ${n + 1} = ${yuvarla(ort, 2).toLocaleString('tr-TR')}`,
+ `SD = ${yuvarla(ort, 2).toLocaleString('tr-TR')} × R(${R}) = ${sd.toLocaleString('tr-TR')} TL`,
+ ],
+ };
+}
+
+/** Personel çalıştırılmasına dayalı hizmet — Md. 79.1.1 */
+export function sinirDegerPersonel({ karHaricYm }) {
+ const v = sayi(karHaricYm);
+ if (!(v > 0)) return { hata: 'Kâr hariç yaklaşık maliyet gerekli' };
+ return { tur: 'personel', sd: yuvarla(v, 2), adimlar: ['Md. 79.1.1: kâr hariç yaklaşık maliyet tutarı sınır değer kabul edilir.'] };
+}
+
+/** Yapım — Md. 45.1.1 */
+export function sinirDegerYapim({ ym, teklifler, n: N = 1.2 }) {
+ const YM = sayi(ym); const Nk = Number(N);
+ if (!(YM > 0)) return { hata: 'Yaklaşık maliyet gerekli' };
+ const dahil = teklifler.filter((t) => t >= YM * 0.4 && t <= YM * 1.2);
+ const haric1 = teklifler.filter((t) => t < YM * 0.4 || t > YM * 1.2);
+ if (dahil.length < 2) return { hata: 'Aralıkta en az iki geçerli teklif olmalı' };
+ const tort1 = yuvarla(dahil.reduce((a, b) => a + b, 0) / dahil.length, 2);
+ const sigma = yuvarla(Math.sqrt(dahil.reduce((a, t) => a + (t - tort1) ** 2, 0) / (dahil.length - 1)), 2);
+ const alt = yuvarla(tort1 - sigma, 2), ust = yuvarla(tort1 + sigma, 2);
+ const bant = dahil.filter((t) => t >= alt && t <= ust);
+ const haric2 = dahil.filter((t) => t < alt || t > ust);
+ if (!bant.length) return { hata: 'Standart sapma aralığında teklif kalmadı' };
+ const tort2 = yuvarla(bant.reduce((a, b) => a + b, 0) / bant.length, 2);
+ const C = yuvarla(tort2 / YM, 3);
+ let K, kFormul;
+ if (C < 0.6) { K = C; kFormul = 'C < 0,60 → K = C'; }
+ else if (C <= 1.0) { K = yuvarla((3.2 * C - C * C - 0.6) / (C + 1), 3); kFormul = '0,60 ≤ C ≤ 1,00 → K = (3,2C − C² − 0,6)/(C + 1)'; }
+ else { K = yuvarla((C * C - 0.8 * C + 1.4) / (C + 1), 3); kFormul = 'C > 1,00 → K = (C² − 0,8C + 1,4)/(C + 1)'; }
+ const sd = yuvarla((K * tort2) / (C * Nk), 2);
+ const f = (x) => x.toLocaleString('tr-TR');
+ return {
+ tur: 'yapim', sd, ym: YM, n: Nk, tort1, sigma, alt, ust, tort2, C, K, dahil, bant, haric: [...haric1, ...haric2],
+ adimlar: [
+ `YM'nin %120 üstü (${f(YM * 1.2)}) ve %40 altı (${f(YM * 0.4)}) hariç: ${haric1.length} teklif dışarıda, ${dahil.length} teklif ortalamaya girdi`,
+ `Tort1 = ${f(tort1)} · σ = ${f(sigma)} · aralık [${f(alt)} , ${f(ust)}]`,
+ `Aralıkta kalan ${bant.length} teklif → Tort2 = ${f(tort2)} (${haric2.length} teklif aralık dışı)`,
+ `C = Tort2 / YM = ${C}`,
+ `${kFormul} → K = ${K}`,
+ `SD = (K × Tort2) / (C × N) = (${K} × ${f(tort2)}) / (${C} × ${Nk}) = ${f(sd)} TL`,
+ ],
+ };
+}