security: escape formula-like price csv cells

This commit is contained in:
2026-09-06 16:38:46 +03:00
parent 2bdc89286c
commit 529556fd17
2 changed files with 12 additions and 2 deletions
+5
View File
@@ -1365,6 +1365,11 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö
- Fiyat analizi CSV dışa aktarımında min/medyan/ortalama/maksimum değerleri artık yuvarlanıp kuruş kaybetmiyor; iki ondalık basamakla aynı ham istatistikleri taşıyor. - Fiyat analizi CSV dışa aktarımında min/medyan/ortalama/maksimum değerleri artık yuvarlanıp kuruş kaybetmiyor; iki ondalık basamakla aynı ham istatistikleri taşıyor.
- Ekrandaki yuvarlanmış grafik sunumu korunuyor; indirilen rapor hesaplama denetimi için daha hassas değer içeriyor. 283 test ve build başarılı. CSV’nin gerçek tarayıcıda indirilip açılması henüz doğrulanmadı; genel plan açık. - Ekrandaki yuvarlanmış grafik sunumu korunuyor; indirilen rapor hesaplama denetimi için daha hassas değer içeriyor. 283 test ve build başarılı. CSV’nin gerçek tarayıcıda indirilip açılması henüz doğrulanmadı; genel plan açık.
### 2026-09-06 — Fiyat analizi CSV formül güvenliği
- CSV dışa aktarımında ürün adı, birim ve diğer hücreler artık Excel formülü başlangıç karakterlerine karşı kaçışlanıyor; `=`, `+`, `-`, `@` ile başlayan kaynak metinler çalışma kitabı formülü olarak çalıştırılmıyor.
- Tüm alanlar tırnaklanıp çift tırnaklar kaçışlanıyor; kuruş hassasiyeti korunuyor. 283 test ve build başarılı. CSV’nin gerçek Excel/LibreOffice açılış kabulü henüz yapılmadı; genel plan açık.
### 2026-09-06 — Belge son kullanma tarihi doğrulaması ### 2026-09-06 — Belge son kullanma tarihi doğrulaması
- Belge deposundaki son kullanma tarihi göstergesi artık yalnız geçerli ISO günlerini hesaplıyor. Bozuk veya yuvarlanabilir bir tarih sessizce gün hesabına girmiyor; kullanıcıya “Tarih doğrulanmalı” uyarısı gösteriliyor. - Belge deposundaki son kullanma tarihi göstergesi artık yalnız geçerli ISO günlerini hesaplıyor. Bozuk veya yuvarlanabilir bir tarih sessizce gün hesabına girmiyor; kullanıcıya “Tarih doğrulanmalı” uyarısı gösteriliyor.
+7 -2
View File
@@ -6,6 +6,11 @@ import { itemStats } from '../../services/analytics';
import confetti from 'canvas-confetti'; import confetti from 'canvas-confetti';
const formatPrice = (n) => n == null || !Number.isFinite(Number(n)) ? '—' : Number(n).toLocaleString('tr-TR', {minimumFractionDigits:2, maximumFractionDigits:2}) + ' ₺'; const formatPrice = (n) => n == null || !Number.isFinite(Number(n)) ? '—' : Number(n).toLocaleString('tr-TR', {minimumFractionDigits:2, maximumFractionDigits:2}) + ' ₺';
const csvCell = value => {
const text = String(value ?? '');
const safe = /^[=+\-@]/.test(text) ? `'${text}` : text;
return `"${safe.replace(/"/g, '""')}"`;
};
export const PriceAnalysis = () => { export const PriceAnalysis = () => {
const { tenders } = useApp(); const { tenders } = useApp();
@@ -37,8 +42,8 @@ export const PriceAnalysis = () => {
if (!items.length) return; if (!items.length) return;
const headers = ['Kalem', 'Birim', 'Adet(kayıt)', 'Min', 'Medyan', 'Ortalama', 'Maks']; const headers = ['Kalem', 'Birim', 'Adet(kayıt)', 'Min', 'Medyan', 'Ortalama', 'Maks'];
const rows = items.map((i) => [ const rows = items.map((i) => [
`"${(i.ad || '').replace(/"/g, '""')}"`, i.birim || '', i.count, csvCell(i.ad), csvCell(i.birim), csvCell(i.count),
i.min.toFixed(2), i.median.toFixed(2), i.avg.toFixed(2), i.max.toFixed(2), csvCell(i.min.toFixed(2)), csvCell(i.median.toFixed(2)), csvCell(i.avg.toFixed(2)), csvCell(i.max.toFixed(2)),
]); ]);
const csv = 'data:text/csv;charset=utf-8,' + [headers.join(','), ...rows.map((r) => r.join(','))].join('\n'); const csv = 'data:text/csv;charset=utf-8,' + [headers.join(','), ...rows.map((r) => r.join(','))].join('\n');
const link = document.createElement('a'); const link = document.createElement('a');