Refactor earnings calculations in WorkdayService and CompensationCalculator to use BigDecimal for precision and apply consistent rounding#45
Conversation
…ulator to use BigDecimal for precision and apply consistent rounding
Test Results47 tests 47 ✅ 0s ⏱️ Results for commit 1df3762. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Pull request overview
This PR refactors compensation/earnings calculations to use BigDecimal end-to-end for higher precision, standardizes intermediate division precision, and defers rounding until returning monthly totals to avoid cumulative day-by-day rounding drift.
Changes:
- Accumulate monthly
workedEarningsasBigDecimalinWorkdayServiceand round only once when returning the monthly total. - Standardize monetary division precision in
CompensationCalculatorviaMONEY_SCALE, and avoid premature rounding incalculateEarnings. - Update calculator tests to assert precise
BigDecimaloutputs and add a regression test to validate “round only at monthly total” behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/main/kotlin/com/moa/service/WorkdayService.kt | Switch monthly earnings accumulation to BigDecimal and apply consistent rounding at response boundaries. |
| src/main/kotlin/com/moa/service/calculator/CompensationCalculator.kt | Introduce MONEY_SCALE and adjust daily-rate / earnings calculations to preserve precision until later rounding. |
| src/test/kotlin/com/moa/service/calculator/CompensationCalculatorTest.kt | Update expected values to high-precision BigDecimal and add a monthly-sum rounding test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/test/kotlin/com/moa/service/calculator/CompensationCalculatorTest.kt
Outdated
Show resolved
Hide resolved
src/test/kotlin/com/moa/service/calculator/CompensationCalculatorTest.kt
Outdated
Show resolved
Hide resolved
src/test/kotlin/com/moa/service/calculator/CompensationCalculatorTest.kt
Show resolved
Hide resolved
…le exact policy work minutes and update test cases for accuracy
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ): BigDecimal { | ||
| if (policyWorkMinutes <= 0) return dailyRate | ||
| val minuteRate = dailyRate.divide(BigDecimal(policyWorkMinutes), 10, RoundingMode.HALF_UP) | ||
| return minuteRate.multiply(BigDecimal(actualWorkMinutes)).setScale(0, RoundingMode.HALF_UP) | ||
| if (actualWorkMinutes == policyWorkMinutes) return dailyRate | ||
| val minuteRate = dailyRate.divide(BigDecimal(policyWorkMinutes), MONEY_SCALE, RoundingMode.HALF_UP) | ||
| return minuteRate.multiply(BigDecimal(actualWorkMinutes)) |
There was a problem hiding this comment.
calculateEarnings returns dailyRate directly when actualWorkMinutes == policyWorkMinutes, but returns a multiplied value (with MONEY_SCALE decimals) otherwise. Because BigDecimal equality is scale-sensitive (e.g., 100000 != 100000.0000000000), this introduces inconsistent scales depending on the branch, which can cause subtle bugs if callers use equals/hashing or serialize values. Consider normalizing the scale of the returned value (e.g., always setScale(MONEY_SCALE, ...) or stripTrailingZeros() consistently) before returning.
There was a problem hiding this comment.
BigDecimal scale inconsistency point is valid in general, but in this flow values are normalized at response boundaries via setScale(0, HALF_UP), and comparisons use compareTo semantics. So it should not affect current behavior. I’d prefer to avoid additional intermediate normalization here because that would reintroduce rounding into the calculation path we just fixed.
This pull request refines the way earnings are calculated and rounded in the compensation logic, ensuring greater precision and consistency between daily and monthly totals. The main changes involve switching from integer-based to
BigDecimal-based calculations for earnings, delaying rounding until the monthly total is computed, and updating tests to reflect these changes.Earnings Calculation and Rounding Improvements:
workedEarningsinWorkdayServicefromLongtoBigDecimal, and now only rounds to the nearest integer when returning the monthly total. This prevents rounding errors from accumulating day-by-day. [1] [2]BigDecimaland round only at the point of returning integer results, ensuring consistency in rounding logic.MONEY_SCALEinCompensationCalculatorto standardize decimal precision in monetary calculations.CompensationCalculatorto useMONEY_SCALEfor division and to avoid premature rounding, improving accuracy. [1] [2]Test Updates:
BigDecimalvalues instead of rounded integers, reflecting the new calculation logic. [1] [2] [3] [4] [5] [6] [7] [8] [9]Other:
RoundingModein relevant files. [1] [2]