fix: separate item price analysis by unit

This commit is contained in:
2026-09-06 16:32:16 +03:00
parent 07cfd6198f
commit 04f24d78a3
3 changed files with 24 additions and 2 deletions
+6
View File
@@ -1324,6 +1324,12 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö
- Analitik `parseDateTR`, JavaScript tarih yuvarlamasıyla 31 Şubat gibi imkânsız günleri geçerli tarihe dönüştürmüyordu; artık gün/ay/yıl bileşenlerini doğrulayıp geçersiz girdide `null` döndürüyor. Geçersiz tarihler yanlış hafta sonu veya kısa süre riskine dönüşmüyor. - Analitik `parseDateTR`, JavaScript tarih yuvarlamasıyla 31 Şubat gibi imkânsız günleri geçerli tarihe dönüştürmüyordu; artık gün/ay/yıl bileşenlerini doğrulayıp geçersiz girdide `null` döndürüyor. Geçersiz tarihler yanlış hafta sonu veya kısa süre riskine dönüşmüyor.
- 31.02.2026 reddi, artık yıl 29.02.2028 ve eğik çizgili geçerli tarih için regresyon testleri eklendi. 281 test ve build başarılı. Genel plan açık. - 31.02.2026 reddi, artık yıl 29.02.2028 ve eğik çizgili geçerli tarih için regresyon testleri eklendi. 281 test ve build başarılı. Genel plan açık.
### 2026-09-06 — Fiyat analizinde birim ve miktar ayrımı
- D08 kapsamında `itemStats` aynı ürün adının kutu, adet veya başka birimlerdeki fiyatlarını artık tek medyanda birleştirmiyor. İstatistik anahtarı ürün + birim olarak ayrıldı.
- Miktarı veya birimi kaynakta bilinmeyen kalemler fiyat analizine alınmıyor; böylece birim fiyat karşılaştırması doğrulanmamış kapsamla öneri üretmiyor.
- Kutu/adet ve bilinmeyen miktar regresyonu eklendi. 282 test ve build başarılı. Gerçek pazar verisiyle fiyat karşılaştırması ve kur kaynağı kabulü hâlâ plan maddesi; 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.
+8 -2
View File
@@ -83,6 +83,8 @@ export function firmStats(tenders) {
}; };
} }
import { quantityParts } from './bidValidation.js';
// --- Kalem bazlı fiyat analizi --- // --- Kalem bazlı fiyat analizi ---
export function itemStats(tenders) { export function itemStats(tenders) {
const map = new Map(); const map = new Map();
@@ -92,8 +94,12 @@ export function itemStats(tenders) {
const bf = parseTL(it.birimFiyat); const bf = parseTL(it.birimFiyat);
if (bf == null) continue; if (bf == null) continue;
itemCount++; itemCount++;
const key = (it.ad || 'Diğer').trim().toLocaleUpperCase('tr-TR'); const quantity=quantityParts(it.miktar ?? it.quantity);
const cur = map.get(key) || { ad: it.ad, birim: it.birim, count: 0, prices: [] }; const rawUnit=quantity.birim || it.birim || '';
if (quantity.miktar == null || !String(rawUnit).trim()) { itemCount--; continue; }
const unit=String(rawUnit).trim().toLocaleLowerCase('tr-TR');
const key = `${(it.ad || 'Diğer').trim().toLocaleUpperCase('tr-TR')}||${unit}`;
const cur = map.get(key) || { ad: it.ad, birim: unit, count: 0, prices: [] };
cur.count++; cur.count++;
cur.prices.push(bf); cur.prices.push(bf);
map.set(key, cur); map.set(key, cur);
+10
View File
@@ -6,6 +6,16 @@ test('analytics rejects impossible Turkish calendar dates instead of rolling the
assert.equal(parseDateTR('29.02.2028')?.getDate(),29); assert.equal(parseDateTR('29.02.2028')?.getDate(),29);
assert.equal(parseDateTR('30/04/2026')?.getMonth(),3); assert.equal(parseDateTR('30/04/2026')?.getMonth(),3);
}); });
test('item price analysis separates units and ignores unknown quantities',async()=>{
const {itemStats}=await import('../src/services/analytics.js');
const result=itemStats([{items:[
{ad:'Test kiti',miktar:'2 kutu',birimFiyat:'10 TL'},
{ad:'Test kiti',miktar:'3 adet',birimFiyat:'12 TL'},
{ad:'Test kiti',miktar:'bilinmiyor',birimFiyat:'99 TL'},
]}]);
assert.equal(result.itemCount,2); assert.equal(result.uniqueItems,2);
assert.deepEqual(result.items.map(x=>x.birim).sort(),['adet','kutu']);
});
import {hizliFiltreGecer} from '../src/services/ihaleTarih.js'; import {hizliFiltreGecer} from '../src/services/ihaleTarih.js';
import {applyTenderStates} from '../src/services/tenderState.js'; import {applyTenderStates} from '../src/services/tenderState.js';
test('review counter uses the same explicit state as reviewed and unread filters',()=>{ test('review counter uses the same explicit state as reviewed and unread filters',()=>{