fix: preserve Turkish decimal prices and verify preparation persistence
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { bidRowTotal, validateBidRows, roundMoney } from '../services/bidValidation';
|
||||
import { bidRowTotal, validateBidRows, roundMoney, parseBidPrice } from '../services/bidValidation';
|
||||
import { sourceRows, bidSourceSnapshot, restoreBidPrices } from '../services/bidSource';
|
||||
import { PreparationChecks } from './PreparationChecks';
|
||||
import { preparationBlockers, documentKey } from '../services/preparationChecks';
|
||||
@@ -91,7 +91,7 @@ export const BidPackageBuilder = ({ results, tender: selectedTender }) => {
|
||||
else setHata('Taslak kaydedilemedi. Tekrar deneyin.');
|
||||
};
|
||||
|
||||
const toplam = teklifTuru === 'goturu' ? (Number(goturuBedel) || 0) : kalemToplami;
|
||||
const toplam = teklifTuru === 'goturu' ? (parseBidPrice(goturuBedel) || 0) : kalemToplami;
|
||||
|
||||
const eksikler = ALANLAR.filter((a) => a.zorunlu && !String(firma[a.k] || '').trim());
|
||||
const kalemEksik = teklifTuru === 'birim' && validateBidRows(satirlar).length > 0;
|
||||
@@ -246,7 +246,7 @@ export const BidPackageBuilder = ({ results, tender: selectedTender }) => {
|
||||
</span>
|
||||
<input
|
||||
value={goturuBedel}
|
||||
onChange={(e) => setGoturuBedel(e.target.value.replace(/[^\d.]/g, ''))}
|
||||
onChange={(e) => setGoturuBedel(e.target.value)}
|
||||
placeholder="0"
|
||||
className="w-full sm:w-64 text-sm font-bold px-3 py-2 rounded-lg border border-slate-300"
|
||||
/>
|
||||
@@ -254,6 +254,7 @@ export const BidPackageBuilder = ({ results, tender: selectedTender }) => {
|
||||
) : kalemler.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
<h5 className="font-extrabold text-xs text-slate-900">Kalem fiyatlandırma</h5>
|
||||
<p className="text-xs text-slate-500">Ondalık fiyatı 125,50 veya 125.50 biçiminde yazın; binlik ayırıcı kullanmayın.</p>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-xs min-w-[520px]">
|
||||
<thead>
|
||||
@@ -278,7 +279,7 @@ export const BidPackageBuilder = ({ results, tender: selectedTender }) => {
|
||||
<input
|
||||
value={fiyatlar[r.priceKey] ?? ''}
|
||||
onChange={(e) =>
|
||||
setFiyatlar((o) => ({ ...o, [r.priceKey]: e.target.value.replace(/[^\d.]/g, '') }))}
|
||||
setFiyatlar((o) => ({ ...o, [r.priceKey]: e.target.value }))}
|
||||
placeholder={r.estimatedUnitPrice != null ? String(r.estimatedUnitPrice) : '0'}
|
||||
className="w-28 text-xs text-right px-2 py-1 rounded border border-slate-300"
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { quantityParts, bidRowTotal, validateBidRows } from './bidValidation.js';
|
||||
import { quantityParts, parseBidPrice, bidRowTotal, validateBidRows } from './bidValidation.js';
|
||||
/**
|
||||
* İhale dosyası belgeleri — teklif mektubu, birim fiyat teklif cetveli ve
|
||||
* evrak kontrol listesi.
|
||||
@@ -162,7 +162,7 @@ export function teklifCetveliHtml(f, satirlar, toplam) {
|
||||
if (errors.length) throw new Error(errors.join(" "));
|
||||
const govde = satirlar.map((r, i) => {
|
||||
const { miktar, birim } = miktarAyristir(r.quantity);
|
||||
const bf = Number(r.birimFiyat) || 0;
|
||||
const bf = parseBidPrice(r.birimFiyat);
|
||||
const tutar = bidRowTotal(r);
|
||||
return `<tr>
|
||||
<td class="s">${i + 1}</td>
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// Preserve typed input; never delete a decimal separator and change its value.
|
||||
export function parseBidPrice(value) {
|
||||
if (typeof value === 'number') return Number.isFinite(value) && value >= 0 ? value : null;
|
||||
const text = String(value ?? '').trim();
|
||||
const plain = /^\d+(?:[.,]\d{1,8})?$/;
|
||||
const groupedTurkish = /^\d{1,3}(?:\.\d{3})+,\d{1,8}$/;
|
||||
if (!plain.test(text) && !groupedTurkish.test(text)) return null;
|
||||
const normalized = text.includes(',') ? text.replace(/\./g,'').replace(',','.') : text;
|
||||
const result = Number(normalized);
|
||||
return Number.isFinite(result) ? result : null;
|
||||
}
|
||||
export function quantityParts(value) {
|
||||
if (typeof value === 'number') return {miktar:Number.isFinite(value) ? value : null,birim:''};
|
||||
const match = /^\s*([+-]?[\d]+(?:[.,]\d+)*)\s+(.+?)\s*$/.exec(String(value || ''));
|
||||
@@ -11,8 +22,9 @@ export function quantityParts(value) {
|
||||
export const roundMoney = n => Math.round((n + Number.EPSILON) * 100) / 100;
|
||||
export function bidRowTotal(row) {
|
||||
const {miktar} = quantityParts(row.quantity);
|
||||
const price = Number(row.birimFiyat);
|
||||
return miktar > 0 && Number.isFinite(price) && price > 0 ? roundMoney(miktar * price) : null;
|
||||
const price = parseBidPrice(row.birimFiyat);
|
||||
const total = miktar * price;
|
||||
return miktar > 0 && price > 0 && Number.isFinite(total) && total <= Number.MAX_SAFE_INTEGER / 100 ? roundMoney(total) : null;
|
||||
}
|
||||
export function validateBidRows(rows) {
|
||||
if (!rows.length) return ['Resmi teklif cetvelindeki kalemler eksik.'];
|
||||
|
||||
Reference in New Issue
Block a user