normalize tender result status in dedupe
This commit is contained in:
@@ -2260,3 +2260,9 @@ Doğrulama: browserTimezone `America/New_York`, mobil viewport 390 px ve yatay t
|
|||||||
Canlı drift probe’u artık API yanıt gövdesini de doğruluyor: `/api/health` için `ok:true`, `/api/ready` için `success:true` ve JSON içerik türü aranıyor. Böylece HTTP 200 dönen SPA/ara hata sayfaları sağlıklı servis kabul edilmiyor.
|
Canlı drift probe’u artık API yanıt gövdesini de doğruluyor: `/api/health` için `ok:true`, `/api/ready` için `success:true` ve JSON içerik türü aranıyor. Böylece HTTP 200 dönen SPA/ara hata sayfaları sağlıklı servis kabul edilmiyor.
|
||||||
|
|
||||||
Güncel canlı sonuçta health `ok:true` olsa da readiness `404` ve güvenlik başlıkları eksik olduğu için probe başarısız kaldı; kanıt `qa-live-runtime.json` içinde.
|
Güncel canlı sonuçta health `ok:true` olsa da readiness `404` ve güvenlik başlıkları eksik olduğu için probe başarısız kaldı; kanıt `qa-live-runtime.json` içinde.
|
||||||
|
|
||||||
|
### 2026-09-06 · D04 sonuç durumu normalizasyonu
|
||||||
|
|
||||||
|
Kaynaklar `Sonuçlandı` durumunu boşluk veya büyük/küçük harf farkıyla döndürdüğünde tekilleştirme artık aynı award anahtarını kullanıyor. Lot numarası hâlâ kimliğin parçası; farklı kısımlar birbirine karışmıyor ve aynı lotun farklı kaynak kayıtları birleşiyor.
|
||||||
|
|
||||||
|
Doğrulama: yeni regresyonla otomatik test sayısı 295/295’e yükseldi; üretim derlemesi başarılı.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const norm = v => String(v || '').trim().replace(/\s+/g,' ').toLocaleLowerCase('
|
|||||||
export function tenderIdentity(t) {
|
export function tenderIdentity(t) {
|
||||||
const ikn = String(t.ikn || '').replace(/\s/g,'');
|
const ikn = String(t.ikn || '').replace(/\s/g,'');
|
||||||
// Awards from different lots must never be collapsed into one contract.
|
// Awards from different lots must never be collapsed into one contract.
|
||||||
if (t.durum === 'Sonuçlandı') return `award:${ikn}:${t.kisim ?? t.id}:${norm(t.kazananFirma)}`;
|
if (norm(t.durum) === 'sonuçlandı') return `award:${ikn}:${t.kisim ?? t.id}:${norm(t.kazananFirma)}`;
|
||||||
if (/^\d{2}DT\d+$/i.test(ikn)) return `dt:${ikn.toUpperCase()}:${norm(t.kurum)}`;
|
if (/^\d{2}DT\d+$/i.test(ikn)) return `dt:${ikn.toUpperCase()}:${norm(t.kurum)}`;
|
||||||
// Corrections/cancellations remain separate events until their source linkage is verified.
|
// Corrections/cancellations remain separate events until their source linkage is verified.
|
||||||
if (/düzeltme|zeyilname|iptal/i.test(t.baslik || '')) return `event:${t.id}`;
|
if (/düzeltme|zeyilname|iptal/i.test(t.baslik || '')) return `event:${t.id}`;
|
||||||
|
|||||||
@@ -11,6 +11,13 @@ test('distinct contract lots and corrections remain separate',()=>{
|
|||||||
assert.equal(uniqueTenders([t,t,{...t,id:'b',kisim:'2'}]).length,2);
|
assert.equal(uniqueTenders([t,t,{...t,id:'b',kisim:'2'}]).length,2);
|
||||||
assert.equal(uniqueTenders([{ikn:'2026/123',id:'1'},{ikn:'2026/123',id:'2',baslik:'Düzeltme ilanı'}]).length,2);
|
assert.equal(uniqueTenders([{ikn:'2026/123',id:'1'},{ikn:'2026/123',id:'2',baslik:'Düzeltme ilanı'}]).length,2);
|
||||||
});
|
});
|
||||||
|
test('result status whitespace is normalized without collapsing distinct lots',()=>{
|
||||||
|
const first={ikn:'2026/456',durum:' Sonuçlandı ',kisim:'1',id:'a',kazananFirma:'Firma'};
|
||||||
|
const same={...first,id:'b'};
|
||||||
|
const other={...first,id:'c',kisim:'2'};
|
||||||
|
const out=uniqueTenders([first,same,other]);
|
||||||
|
assert.equal(out.length,2);assert.deepEqual(out[0].sourceIds,['a','b']);
|
||||||
|
});
|
||||||
test('malformed source rows do not crash pool deduplication',()=>{
|
test('malformed source rows do not crash pool deduplication',()=>{
|
||||||
const out=uniqueTenders([null,42,{},[],{ikn:'2026/123',baslik:'Eksik kimlik'}]);
|
const out=uniqueTenders([null,42,{},[],{ikn:'2026/123',baslik:'Eksik kimlik'}]);
|
||||||
assert.deepEqual(out,[]);
|
assert.deepEqual(out,[]);
|
||||||
|
|||||||
Reference in New Issue
Block a user