security: escape formula-like price csv cells
This commit is contained in:
@@ -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.
|
||||
- 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ı
|
||||
|
||||
- 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.
|
||||
|
||||
@@ -6,6 +6,11 @@ import { itemStats } from '../../services/analytics';
|
||||
import confetti from 'canvas-confetti';
|
||||
|
||||
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 = () => {
|
||||
const { tenders } = useApp();
|
||||
@@ -37,8 +42,8 @@ export const PriceAnalysis = () => {
|
||||
if (!items.length) return;
|
||||
const headers = ['Kalem', 'Birim', 'Adet(kayıt)', 'Min', 'Medyan', 'Ortalama', 'Maks'];
|
||||
const rows = items.map((i) => [
|
||||
`"${(i.ad || '').replace(/"/g, '""')}"`, i.birim || '', i.count,
|
||||
i.min.toFixed(2), i.median.toFixed(2), i.avg.toFixed(2), i.max.toFixed(2),
|
||||
csvCell(i.ad), csvCell(i.birim), csvCell(i.count),
|
||||
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 link = document.createElement('a');
|
||||
|
||||
Reference in New Issue
Block a user