fix: počítání částek v haléřích z důvodu přesnosti
CI / Generate TypeScript types (push) Successful in 21s
CI / Build server (push) Successful in 25s
CI / Server unit tests (push) Successful in 55s
CI / Build client (push) Successful in 33s
CI / Playwright E2E tests (push) Successful in 1m20s
CI / Build and push Docker image (push) Successful in 35s
CI / Notify (push) Successful in 2s

This commit is contained in:
2026-05-07 13:09:15 +02:00
parent d91c8db49c
commit 8aef00ab05
18 changed files with 370 additions and 380 deletions
@@ -9,18 +9,23 @@ type Props = {
onSaved: (data: any) => void;
};
function parseNum(s: string): number {
function parseHal(s: string): number {
const n = parseFloat(s.replace(',', '.'));
return isNaN(n) || n < 0 ? 0 : Math.round(n * 100) / 100;
return isNaN(n) || n < 0 ? 0 : Math.round(n * 100);
}
function parsePercent(s: string): number {
const n = parseFloat(s.replace(',', '.'));
return isNaN(n) || n < 0 ? 0 : Math.round(n);
}
function computeMemberTotal(member: OrderGroupMember, feeShare: number, discountType: string, discountValue: number, memberCount: number): number {
const base = member.amount ?? 0;
const surcharge = member.surchargeAmount ?? 0;
const discount = discountType === 'percent'
? Math.round((base + surcharge) * discountValue / 100 * 100) / 100
: Math.round(discountValue / memberCount * 100) / 100;
return Math.round((base + surcharge + feeShare - discount) * 100) / 100;
? Math.round((base + surcharge) * discountValue / 100)
: Math.round(discountValue / memberCount);
return base + surcharge + feeShare - discount;
}
export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }: Readonly<Props>) {
@@ -34,23 +39,25 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }:
useEffect(() => {
if (!isOpen) return;
setFees(group.fees ? String(group.fees) : '');
setShipping(group.shipping ? String(group.shipping) : '');
setTip(group.tip ? String(group.tip) : '');
setFees(group.fees ? String(group.fees / 100) : '');
setShipping(group.shipping ? String(group.shipping / 100) : '');
setTip(group.tip ? String(group.tip / 100) : '');
setDiscountType((group.discountType as 'percent' | 'fixed') ?? 'percent');
setDiscountValue(group.discountValue ? String(group.discountValue) : '');
setDiscountValue(group.discountValue
? ((group.discountType as string) === 'fixed' ? String(group.discountValue / 100) : String(group.discountValue))
: '');
setError(null);
}, [isOpen, group]);
const memberEntries = Object.entries(group.members) as [string, OrderGroupMember][];
const memberCount = memberEntries.length;
const feesNum = parseNum(fees);
const shippingNum = parseNum(shipping);
const tipNum = parseNum(tip);
const discountNum = parseNum(discountValue);
const feesNum = parseHal(fees);
const shippingNum = parseHal(shipping);
const tipNum = parseHal(tip);
const discountNum = discountType === 'percent' ? parsePercent(discountValue) : parseHal(discountValue);
const totalFees = feesNum + shippingNum + tipNum;
const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount * 100) / 100 : 0;
const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount) : 0;
const handleSave = async () => {
setError(null);
@@ -64,7 +71,7 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }:
tip: tipNum,
discountType: discountNum > 0 ? discountType : undefined,
discountValue: discountNum > 0 ? discountNum : undefined,
},
}
});
if (res.error) {
setError((res.error as any).error || 'Nastala chyba');
@@ -143,7 +150,7 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }:
</div>
<hr />
<h6>Náhled celkových částek ({memberCount} členů, {feeShare > 0 ? `poplatek ${feeShare} Kč/os.` : 'bez poplatku'})</h6>
<h6>Náhled celkových částek ({memberCount} členů, {feeShare > 0 ? `poplatek ${feeShare / 100} Kč/os.` : 'bez poplatku'})</h6>
<Table size="sm" bordered>
<thead>
<tr>
@@ -161,18 +168,18 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }:
const surcharge = member.surchargeAmount ?? 0;
const discount = discountNum > 0
? (discountType === 'percent'
? Math.round((base + surcharge) * discountNum / 100 * 100) / 100
: Math.round(discountNum / memberCount * 100) / 100)
? Math.round((base + surcharge) * discountNum / 100)
: Math.round(discountNum / memberCount))
: 0;
const total = computeMemberTotal(member, feeShare, discountType, discountNum, memberCount);
return (
<tr key={login}>
<td><strong>{login}</strong></td>
<td className="text-end">{base > 0 ? `${base}` : '—'}</td>
<td className="text-end">{surcharge > 0 ? `${surcharge}` : '—'}</td>
<td className="text-end">{feeShare > 0 ? `${feeShare}` : '—'}</td>
<td className="text-end text-danger">{discount > 0 ? `-${discount}` : '—'}</td>
<td className="text-end fw-bold">{total > 0 ? `${total}` : '—'}</td>
<td className="text-end">{base > 0 ? `${base / 100}` : '—'}</td>
<td className="text-end">{surcharge > 0 ? `${surcharge / 100}` : '—'}</td>
<td className="text-end">{feeShare > 0 ? `${feeShare / 100}` : '—'}</td>
<td className="text-end text-danger">{discount > 0 ? `-${discount / 100}` : '—'}</td>
<td className="text-end fw-bold">{total > 0 ? `${total / 100}` : '—'}</td>
</tr>
);
})}