You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up from #3379 / PR #3380, flagged during that fix's self-review.
classes/helpers/FrmCurrencyHelper.php's prepare_price()/maybe_use_decimal() (lines ~95-134) implements the same "strip thousand separator, then blindly swap decimal separator to ." algorithm that FrmTransLiteActionsController::prepare_amount() had, and has the identical root-cause bug: it never checks whether the amount string already contains the currency's other configured separator character in a conflicting role.
Repro (traced, not yet turned into a failing test in that PR since it's a different consumer): a EUR-configured currency (decimal_separator=',', thousand_separator='.') fed a US-style amount "1,030.21":
maybe_use_decimal() sees thousand_separator === '.', finds one . with a 2-digit tail, treats it as a misplaced decimal point, and rewrites it: "1,030,21".
prepare_price() then does str_replace(',', '.', ...) on every comma: "1.030.21".
Consumer:FrmFieldTotal (classes/models/fields/FrmFieldTotal.php:108,116,131) calls FrmCurrencyHelper::prepare_price() for Total field price calculations — so this affects Total field math, not payment charges directly, but it's the same class of silent-wrong-money bug.
Suggested fix: apply the same approach PR #3380 used in FrmTransLiteActionsController — a single find_decimal_position()-style helper that detects the real decimal separator from the string itself (rightmost separator wins when both appear) instead of trusting the currency's configured separators, then splits/strips rather than blanket-replacing by character (a repeated occurrence of the resolved decimal character has to not collide into a second decimal point either — see PR #3380's second commit for why the naive single-swap version isn't enough).
Given the shared logic between the two classes, this might also be a good opportunity to extract one shared helper instead of maintaining two parallel implementations of the same parsing algorithm — noted by the reuse pass on #3380's self-review, but left out of that PR to keep its diff scoped to the reported issue.
Follow-up from #3379 / PR #3380, flagged during that fix's self-review.
classes/helpers/FrmCurrencyHelper.php'sprepare_price()/maybe_use_decimal()(lines ~95-134) implements the same "strip thousand separator, then blindly swap decimal separator to." algorithm thatFrmTransLiteActionsController::prepare_amount()had, and has the identical root-cause bug: it never checks whether the amount string already contains the currency's other configured separator character in a conflicting role.Repro (traced, not yet turned into a failing test in that PR since it's a different consumer): a EUR-configured currency (
decimal_separator=',',thousand_separator='.') fed a US-style amount"1,030.21":maybe_use_decimal()seesthousand_separator === '.', finds one.with a 2-digit tail, treats it as a misplaced decimal point, and rewrites it:"1,030,21".prepare_price()then doesstr_replace(',', '.', ...)on every comma:"1.030.21".(float)cast on"1.030.21"stops parsing at the second., silently returning1.03— the same ~1000x truncation as Stripe/Trans amount parser silently truncates on locale-mismatched separators #3379.Consumer:
FrmFieldTotal(classes/models/fields/FrmFieldTotal.php:108,116,131) callsFrmCurrencyHelper::prepare_price()for Total field price calculations — so this affects Total field math, not payment charges directly, but it's the same class of silent-wrong-money bug.Suggested fix: apply the same approach PR #3380 used in
FrmTransLiteActionsController— a singlefind_decimal_position()-style helper that detects the real decimal separator from the string itself (rightmost separator wins when both appear) instead of trusting the currency's configured separators, then splits/strips rather than blanket-replacing by character (a repeated occurrence of the resolved decimal character has to not collide into a second decimal point either — see PR #3380's second commit for why the naive single-swap version isn't enough).Given the shared logic between the two classes, this might also be a good opportunity to extract one shared helper instead of maintaining two parallel implementations of the same parsing algorithm — noted by the reuse pass on #3380's self-review, but left out of that PR to keep its diff scoped to the reported issue.