BAH-4464 Fix for Recurring Appointments Generate Inconsistent Appoint…#188
BAH-4464 Fix for Recurring Appointments Generate Inconsistent Appoint…#188lingeswaranTW wants to merge 3 commits intomasterfrom
Conversation
lingeswaranTW
left a comment
There was a problem hiding this comment.
Review for BAH-4464
Clean, well-scoped fix. All recurring appointment occurrences now correctly share the same appointment number. Production code change is minimal and surgical, test coverage is comprehensive.
No blocking issues found.
Acceptance Criteria: 3/3 met
| AC | Status |
|---|---|
| All recurring instances share identical appointment number | ✅ |
| Single appointments generate unique numbers as before | ✅ |
| Retrieved series show consistent numbers | ✅ |
What's done well:
- Smart reuse of existing appointment numbers when adding to an existing recurring series
- 4 unit tests + 3 integration tests covering key scenarios
- Only 1 production file changed — surgical fix with minimal blast radius
37bd308 to
1a055fb
Compare
QA Readiness Report: PR #188PR: BAH-4464 Fix for Recurring Appointments Generate Inconsistent Appointment Numbers Across Occurrences QA Readiness Status✅ READY FOR QA - ALL IMPROVEMENTS COMPLETEDTest coverage meets QA readiness standards. The core bug fix is thoroughly tested at both unit and integration levels with 4 new unit tests and 3 new integration tests. All recommended improvements have been implemented, including database persistence verification in integration tests. Improvements Completed
Test Coverage Summary
Test Pyramid AnalysisThe test pyramid is healthy. Unit tests form the base with focused, fast tests covering the core Findings by Severity
Note: All 4 MINOR issues identified have been addressed and fixed. See details below. 🚫 BLOCKER IssuesNone 🔴 CRITICAL IssuesNone 🟠 MAJOR IssuesNone 🟡 MINOR Issues (All Resolved)🔵 INFO5. Generator exception propagation not testedCategory: Unit The call to 6. Weekly integration test uses loose assertionCategory: Integration
7. AC #2 (non-recurring appointments) relates to unchanged codeCategory: Integration JIRA AC #2 states "Non-recurring appointment creation: A unique appointment number is generated." This PR only changes Acceptance Criteria Coverage
Checklist for DevelopersAll recommended improvements have been implemented:
What's Done Well
|
…ment Numbers Across Occurrences
1a055fb to
7e0346c
Compare
|
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation. |
dd65e4f to
031e87d
Compare
sumaztwcode
left a comment
There was a problem hiding this comment.
Review for BAH-4464
Good fix for the recurring appointment number inconsistency! The functional implementation is correct and the test coverage is thorough.
Found 0 blocking issues, 1 suggestion, and 2 nits.
Acceptance Criteria: 3/3 met
| * Default behavior: generate one number and apply to all (shared number strategy).* | ||
| * @param appointments List of appointments to apply numbers to. Null or empty lists are ignored. | ||
| */ | ||
| default void applyAppointmentNumbers(@NotNull List<Appointment> appointments) { |
There was a problem hiding this comment.
suggestion: This default method places recurring-series batch policy (generate once, share across all) directly in the single-appointment SPI interface. Two concerns:
-
Spring AOP proxy limitation: The interface is annotated
@Transactional, but Spring's JDK dynamic proxies do not interceptdefaultinterface methods — they're invoked directly, bypassing the proxy chain. So@Transactionalhas no runtime effect for this method. If a custom generator'sgenerateAppointmentNumber()interacts with the database (e.g., sequence-based), it would execute outside the active transaction. -
Separation of concerns: The pre-existing
checkAndAssignAppointmentNumberlived entirely inAppointmentRecurringPatternServiceImpl— the service that understands recurring patterns owned the assignment policy. Moving this policy into the generator interface conflates generation strategy (SPI concern) with distribution policy (service concern).
Consider keeping this logic in AppointmentRecurringPatternServiceImpl as a private helper instead — call generateAppointmentNumber(appointments.get(0)) directly from the service and distribute the result. This keeps everything within the service's @Transactional boundary and preserves the interface as a pure single-appointment generation strategy.
| assertNull(appointmentTwo.getAppointmentNumber()); | ||
| } | ||
|
|
||
| @Test(expected = IndexOutOfBoundsException.class) |
There was a problem hiding this comment.
nit: This codifies IndexOutOfBoundsException (a leaked implementation detail from appointments.get(0) in validateAndSave) as expected behavior. Consider adding an explicit guard at the top of validateAndSave with a more descriptive exception:
if (appointments.isEmpty()) {
throw new APIException("Cannot save a recurring pattern with no appointments");
}Then update this test to expect APIException instead.
| * @param appointments List of appointments to apply numbers to. Null or empty lists are ignored. | ||
| */ | ||
| default void applyAppointmentNumbers(@NotNull List<Appointment> appointments) { | ||
| if (appointments == null || appointments.isEmpty()) { |
There was a problem hiding this comment.
nit: The @NotNull annotation on the parameter declares that null is a contract violation, but this line silently accepts null. These send contradictory signals. For consistency with generateAppointmentNumber(@NotNull Appointment) on the same interface (which has no internal null check), consider removing the null branch and keeping only appointments.isEmpty().
| return; | ||
| } | ||
|
|
||
| String sharedNumber = generateAppointmentNumber(appointments.get(0)); |
There was a problem hiding this comment.
question: The appointments list is constructed from new ArrayList<>(appointmentRecurringPattern.getAppointments()) where getAppointments() returns a HashSet with no guaranteed iteration order. So get(0) selects a non-deterministic appointment.
For the current DefaultAppointmentNumberGeneratorImpl (timestamp-based, ignores the appointment parameter) this is harmless. But if a custom generator uses appointment-specific properties to influence the number, the result would vary across runs. Worth documenting this assumption?
There was a problem hiding this comment.
Pre-existing issue so we can ignore this for now.Its a valid one it cannot guarantee order.
a823554 to
7be714c
Compare
7be714c to
031bef2
Compare
|



…ment Numbers Across Occurrences