Skip to content

Commit f80e686

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/epic20-4-schedule10-print-section
2 parents bdfa457 + c5cb22f commit f80e686

120 files changed

Lines changed: 294 additions & 406 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/main/java/ca/bc/gov/nrs/ilcr/dto/base/MaxByteLength.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
* {@code ALL_TAB_COLUMNS} reports {@code CHAR_USED = 'B'} for {@code CAMP_REPORT.CAMP_NAME} (30)
1818
* and {@code CAMP_REPORT.COMMENTS} (4000). {@code @Size} measures Java characters, so a name of 30
1919
* accented or CJK characters satisfies it and then overflows a 30-BYTE column: Oracle raises
20-
* ORA-12899, the service can only map that {@code DataAccessException} to {@code
21-
* ScheduleNotSavedException}, and the licensee gets an opaque 500 on an ordinary save. This
22-
* constraint turns that into a clean 400 at the same field. The character cap stays because it is
23-
* the LEGACY bound (the screen's own {@code maxlength}) and is the tighter one for ASCII input,
24-
* which is effectively all stored data today.
20+
* ORA-12899, the service can only map that {@code DataAccessException} to {@link
21+
* ca.bc.gov.nrs.ilcr.exception.ScheduleNotSavedException ScheduleNotSavedException}, and the
22+
* licensee gets an opaque 500 on an ordinary save. This constraint turns that into a clean 400 at
23+
* the same field. The character cap stays because it is the LEGACY bound (the screen's own {@code
24+
* maxlength}) and is the tighter one for ASCII input, which is effectively all stored data today.
2525
*
2626
* <p><strong>Message.</strong> Each field reuses its existing per-field length key rather than
2727
* introducing a new one, so a byte violation and a character violation are indistinguishable to the
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package ca.bc.gov.nrs.ilcr.dto.base;
2+
3+
/**
4+
* A user-facing message carried on a mutating/confirming response (AD-8/EQ-M3): the LEGACY {@code
5+
* messages.properties} bundle key plus its server-resolved verbatim text. The frontend renders
6+
* {@code text} and never hardcodes SUC/WRN strings.
7+
*
8+
* <p>The canonical, feature-neutral home for this envelope (Story 29.9): it lives in the shared
9+
* {@code dto.base} package so no feature module (schedule1..11, millcontext) has to reach into
10+
* another for it. Structurally identical across every consumer, so the pinned wire contract stays
11+
* uniform (AD-12).
12+
*
13+
* @param key the legacy {@code messages.properties} key (e.g. {@code dataSavedSuccesfullyInfoMsg})
14+
* @param text the resolved verbatim message text (e.g. {@code Data saved successfully})
15+
*/
16+
public record MessageInfo(String key, String text) {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package ca.bc.gov.nrs.ilcr.dto.base;
2+
3+
/**
4+
* Minimal body for a mutating action that returns no document — e.g. {@code DELETE /schedule1},
5+
* {@code DELETE /api/v1/schedule3} (AD-8/EQ-M3). Carries only the success {@link MessageInfo} so
6+
* the frontend renders server text.
7+
*
8+
* <p>The canonical, feature-neutral home for this envelope (Story 29.9): shared {@code dto.base} so
9+
* no feature module reaches into another for it.
10+
*
11+
* @param message the success message (key + verbatim text)
12+
*/
13+
public record MessageResponse(MessageInfo message) {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package ca.bc.gov.nrs.ilcr.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
/**
6+
* Raised when an edit reaches the service without its AR11 optimistic-lock token ({@code
7+
* revisionCount}). The HTTP path normally never gets here — the API's {@code PUT} validates
8+
* {@code @Validated({Default.class, OnUpdate.class})}, which already rejects a null token as a
9+
* clean 400 — but the service unboxes the token to an {@code int}, so this is the belt-and-braces
10+
* guard that keeps any future caller bypassing that group from turning a missing token into an
11+
* NPE-driven 500 (a validation group protects one entry point, not the method).
12+
*
13+
* <p>Deliberately a 400, NOT a coerced 409: a missing token is a malformed request, never a stale
14+
* one — a coerced 409 (e.g. a {@code -1} sentinel that matches no row) would tell the user to
15+
* reload when the real fix is to send the token (the Story 2.1 review lesson). It maps to the same
16+
* {@code revisionCountRequiredErrorMsg} the Bean Validation path produces, so the two routes are
17+
* indistinguishable to a client.
18+
*
19+
* <p>Canonical shared copy (Story 29.11) — one definition for every schedule instead of per-module
20+
* duplicates. {@code extends BusinessException}, so the single base-type {@code @ExceptionHandler}
21+
* maps it unchanged.
22+
*/
23+
public class RevisionCountRequiredException extends BusinessException {
24+
public RevisionCountRequiredException() {
25+
super(HttpStatus.BAD_REQUEST, "revisionCountRequiredErrorMsg");
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package ca.bc.gov.nrs.ilcr.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
/**
6+
* Raised when a write (PUT/DELETE) targets a schedule whose Schedules 1–10 track is not in Draft —
7+
* the server-side Draft gate (AD-9). Legacy enforced this only by disabling the UI, so no legacy
8+
* message text exists and the key text is a recorded deviation (AD-8). Maps to 409.
9+
*
10+
* <p>Canonical shared copy (Story 29.11) — one definition for every schedule instead of per-module
11+
* duplicates. {@code extends BusinessException}, so the single base-type {@code @ExceptionHandler}
12+
* maps it unchanged.
13+
*/
14+
public class ScheduleNotEditableException extends BusinessException {
15+
public ScheduleNotEditableException() {
16+
super(HttpStatus.CONFLICT, "scheduleNotEditableErrorMsg");
17+
}
18+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package ca.bc.gov.nrs.ilcr.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
/**
6+
* Raised when a schedule save/delete fails at the persistence layer (a repository {@code
7+
* DataAccessException}). Maps to 500 with the verbatim legacy {@code scheduleNotSavedErrorMsg}
8+
* ("Schedule could not be saved."). The {@code @Transactional} write boundary rolls back before
9+
* this surfaces, so a retried request can succeed.
10+
*
11+
* <p>Canonical shared copy (Story 29.11) — one definition for every schedule instead of per-module
12+
* duplicates. {@code extends BusinessException}, so the single base-type {@code @ExceptionHandler}
13+
* maps it unchanged.
14+
*/
15+
public class ScheduleNotSavedException extends BusinessException {
16+
public ScheduleNotSavedException() {
17+
super(HttpStatus.INTERNAL_SERVER_ERROR, "scheduleNotSavedErrorMsg");
18+
}
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package ca.bc.gov.nrs.ilcr.exception;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
/**
6+
* Raised when a mutating request carries a {@code revisionCount} that no longer matches the stored
7+
* {@code ILCR_REPORT_SUMMARY.REVISION_COUNT} — a lost-update conflict (AR11 optimistic lock):
8+
* another user saved in between, so the optimistic-lock bump matched 0 rows. Maps to 409 with the
9+
* verbatim {@code scheduleRevisionConflictErrorMsg}. No legacy message text existed (legacy used
10+
* Hibernate {@code @Version}), so the key text is a recorded deviation (AD-8).
11+
*
12+
* <p>Canonical shared copy (Story 29.11) — one definition for every schedule instead of per-module
13+
* duplicates. {@code extends BusinessException}, so the single base-type {@code @ExceptionHandler}
14+
* maps it unchanged.
15+
*/
16+
public class StaleRevisionException extends BusinessException {
17+
public StaleRevisionException() {
18+
super(HttpStatus.CONFLICT, "scheduleRevisionConflictErrorMsg");
19+
}
20+
}

backend/src/main/java/ca/bc/gov/nrs/ilcr/messages/MessageApi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package ca.bc.gov.nrs.ilcr.messages;
22

3-
import ca.bc.gov.nrs.ilcr.schedule1.dto.MessageInfo;
3+
import ca.bc.gov.nrs.ilcr.dto.base.MessageInfo;
44
import org.springframework.http.ResponseEntity;
55
import org.springframework.web.bind.annotation.GetMapping;
66
import org.springframework.web.bind.annotation.RequestMapping;

backend/src/main/java/ca/bc/gov/nrs/ilcr/messages/MessageController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package ca.bc.gov.nrs.ilcr.messages;
22

3-
import ca.bc.gov.nrs.ilcr.schedule1.dto.MessageInfo;
3+
import ca.bc.gov.nrs.ilcr.dto.base.MessageInfo;
44
import java.util.Set;
55
import org.springframework.context.MessageSource;
66
import org.springframework.context.NoSuchMessageException;

backend/src/main/java/ca/bc/gov/nrs/ilcr/millcontext/MillContextService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package ca.bc.gov.nrs.ilcr.millcontext;
22

3+
import ca.bc.gov.nrs.ilcr.dto.base.MessageInfo;
34
import ca.bc.gov.nrs.ilcr.exception.FieldValuesRequiredException;
45
import ca.bc.gov.nrs.ilcr.millcontext.MillContextRepository.StatusDates;
56
import ca.bc.gov.nrs.ilcr.millcontext.MillContextRepository.TrackCodes;
6-
import ca.bc.gov.nrs.ilcr.millcontext.dto.MessageInfo;
77
import ca.bc.gov.nrs.ilcr.millcontext.dto.MillSummary;
88
import ca.bc.gov.nrs.ilcr.millcontext.dto.ReportingYear;
99
import ca.bc.gov.nrs.ilcr.millcontext.dto.TrackStatus;

0 commit comments

Comments
 (0)