diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java
index 8996891c01..6532264cc9 100644
--- a/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java
+++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java
@@ -4,6 +4,8 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import hec.data.RatingException;
import hec.data.cwmsRating.RatingSet;
@@ -54,15 +56,67 @@ public static String jsonToXml(String json) throws IOException, TransformerExcep
ObjectMapper om = new ObjectMapper();
JsonNode jsonNode = om.readTree(json);
-
+ ObjectWriter writer;
XmlMapper mapper = new XmlMapper();
- ObjectWriter writer = mapper.writer()
- .withRootName("ratings");
+ JsonNode ratings = jsonNode.findPath("ratings");
+ writer = mapper.writer()
+ .withRootName("ratings");
+ if (!ratings.isEmpty()) {
+ jsonNode = transformJsonStructure(ratings);
+ }
String xml = writer.writeValueAsString(jsonNode);
return cleanupXml(xml);
}
+ private static JsonNode transformJsonStructure(JsonNode ratingInput) {
+ String ratingSpecs = "rating-specs";
+ String simpleRating = "simple-rating";
+ String ratingTemplates = "rating-templates";
+ String ratings = "ratings";
+ String name = "name";
+ String parametersString = "parameters-string";
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode transformed = mapper.createObjectNode();
+
+ if (ratingInput.has(ratingSpecs)) {
+ JsonNode ratingSpec = ratingInput.get(ratingSpecs).get(0);
+ ObjectNode temp = mapper.createObjectNode();
+ ratingSpec.forEachEntry(temp::set);
+ if (temp.has("name")) {
+ temp.set("rating-spec-id", temp.get("name"));
+ temp.remove("name");
+ }
+ temp.set("active", JsonNodeFactory.instance.booleanNode(true));
+ transformed.set("rating-spec", temp);
+ }
+ if (ratingInput.has(ratingTemplates)) {
+ JsonNode ratingTemplate = ratingInput.get(ratingTemplates).get(0);
+ ObjectNode temp = mapper.createObjectNode();
+ ratingTemplate.forEachEntry(temp::set);
+ if (temp.has(parametersString)) {
+ temp.set("parameters-id", temp.get(parametersString));
+ temp.remove(parametersString);
+ }
+ if (temp.has(name)) {
+ temp.set("template-id", temp.get(name));
+ temp.remove(name);
+ }
+ transformed.set("rating-template", temp);
+ }
+ if (ratingInput.has(ratings) && ratingInput.get(ratings).get(0).has(simpleRating)) {
+ JsonNode rating = ratingInput.get(ratings).get(0).get(simpleRating);
+ ObjectNode temp = mapper.createObjectNode();
+ rating.forEachEntry(temp::set);
+ if (temp.has(name)) {
+ temp.set("rating-spec-id", temp.get(name));
+ temp.remove(name);
+ }
+ transformed.set(simpleRating, temp);
+ }
+ return transformed;
+ }
+
private static String cleanupXml(String xml) throws TransformerException {
// Doing this in steps b/c I'm not good enough at xslt to make it happen at once.
diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java
index 48309a6220..2580c44d28 100644
--- a/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java
+++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java
@@ -28,7 +28,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import cwms.cda.data.dto.VerticalDatumInfo;
-import cwms.cda.data.dto.rating.RatingSpec;
import hec.data.RatingException;
import hec.data.cwmsRating.RatingSet;
import java.io.IOException;
@@ -36,7 +35,6 @@
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
-
import mil.army.usace.hec.cwms.rating.io.jdbc.ConnectionProvider;
import mil.army.usace.hec.cwms.rating.io.jdbc.RatingJdbcFactory;
import org.jetbrains.annotations.Nullable;
@@ -66,6 +64,12 @@ private static String extractOfficeId(String ratingSet) throws JsonProcessingExc
if (!values.isEmpty()) {
//Getting the last instance since the order is template, spec, rating
office = values.get(values.size() - 1).textValue();
+ } else {
+ values = node.findValues("office");
+ if (!values.isEmpty()) {
+ //Getting the last instance since the order is template, spec, rating
+ office = values.get(values.size() - 1).textValue();
+ }
}
return office;
}
diff --git a/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl b/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl
index 0b900f70e8..230921319c 100644
--- a/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl
+++ b/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl
@@ -18,9 +18,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java
index e97f4dd7d5..61d605b38d 100644
--- a/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java
+++ b/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java
@@ -546,5 +546,44 @@ void test_1206_rating_create_xml() throws IOException {
.statusCode(is(HttpServletResponse.SC_CREATED));
}
+ @Test
+ void test_1758_rating_post() throws IOException {
+ TestAccounts.KeyUser user = TestAccounts.KeyUser.SPK_NORMAL;
+ String ratingId = "FSMI.Stage;Flow.EXSA.PRODUCTION";
+ ratingId = ratingId.replaceAll("FSMI", EXISTING_LOC);
+ String body = readResourceFile("cwms/cda/data/dto/rating/rating_post.json");
+ body = body.replaceAll("FSMI", EXISTING_LOC);
+ // Create the set
+ given()
+ .log().ifValidationFails(LogDetail.ALL,true)
+ .contentType(Formats.JSONV2)
+ .accept(Formats.JSONV2)
+ .body(body)
+ .header("Authorization", user.toHeaderValue())
+ .queryParam(OFFICE, SPK)
+ .when()
+ .redirects().follow(true)
+ .redirects().max(3)
+ .post("/ratings")
+ .then()
+ .log().ifValidationFails(LogDetail.ALL,true)
+ .assertThat()
+ .statusCode(is(HttpServletResponse.SC_CREATED));
+
+ given()
+ .log().ifValidationFails(LogDetail.ALL,true)
+ .accept(Formats.JSONV2)
+ .queryParam(OFFICE, SPK)
+ .when()
+ .redirects().follow(true)
+ .redirects().max(3)
+ .get("/ratings/" + ratingId)
+ .then()
+ .log().ifValidationFails(LogDetail.ALL,true)
+ .assertThat()
+ .statusCode(is(HttpServletResponse.SC_OK))
+ .contentType(is(Formats.JSONV2))
+ .body("office-id", is(SPK));
+ }
}
diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json
new file mode 100644
index 0000000000..cd08eb04f0
--- /dev/null
+++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json
@@ -0,0 +1,126 @@
+{
+ "ratings": {
+ "query-info": {
+ "time-of-query": "2026-06-01T16:52:08Z",
+ "process-query": "PT3.394S",
+ "format-output": "PT3.050S",
+ "requested-format": "JSON",
+ "requested-office-id": "SPK",
+ "requested-start-time": "2026-05-31T16:52:08Z",
+ "requested-end-time": "2026-06-01T16:52:08Z",
+ "requested-items": [
+ {
+ "name": "FSMI.Stage;Flow.EXSA.PRODUCTION",
+ "unit": "NATIVE",
+ "datum": "NATIVE"
+ }
+ ],
+ "templates-retrieved": 1,
+ "total-specifications-retrieved": 1,
+ "unique-specifications-retrieved": 1,
+ "total-ratings-retrieved": 1,
+ "unique-ratings-retrieved": 1
+ },
+ "rating-templates": [
+ {
+ "office": "SPK",
+ "name": "Stage;Flow.EXSA",
+ "parameters-string": "Stage;Flow",
+ "version": "EXSA",
+ "ind-parameters": [
+ {
+ "name": "Stage",
+ "value-lookup-in-range": "LINEAR",
+ "value-lookup-below-range": "NEAREST",
+ "value-lookup-above-range": "NEAREST"
+ }
+ ],
+ "dep-parameter": "Flow",
+ "description": null
+ }
+ ],
+ "rating-specs": [
+ {
+ "office": "SPK",
+ "name": "FSMI.Stage;Flow.EXSA.PRODUCTION",
+ "location": "FSMI",
+ "version": "PRODUCTION",
+ "source-agency": null,
+ "time-lookup-in-range": "PREVIOUS",
+ "time-lookup-before-first": "NEAREST",
+ "time-lookup-after-last": "PREVIOUS",
+ "rounding": {
+ "ind-parameters": [
+ "2223456784"
+ ],
+ "dep-parameter": "2223456784"
+ },
+ "description": "FSMI Expanded, Shift-Adjusted PRODUCTION Stream Rating"
+ }
+ ],
+ "ratings": [
+ {
+ "simple-rating": {
+ "office": "SPK",
+ "name": "FSMI.Stage;Flow.EXSA.PRODUCTION",
+ "ind-parameters": [
+ "Stage (ft)"
+ ],
+ "dep-parameter": "Flow (cfs)",
+ "effective-date": "2007-07-11T20:38:00Z",
+ "description": null,
+ "values": [
+ [
+ 17,
+ 114000
+ ],
+ [
+ 18.75,
+ 140000
+ ],
+ [
+ 20.47,
+ 165558
+ ],
+ [
+ 30,
+ 313800
+ ],
+ [
+ 30.4,
+ 320500
+ ],
+ [
+ 30.84,
+ 328800
+ ],
+ [
+ 31,
+ 332200
+ ],
+ [
+ 31.29,
+ 339300
+ ],
+ [
+ 31.4,
+ 342500
+ ],
+ [
+ 31.62,
+ 349500
+ ],
+ [
+ 32.26,
+ 372000
+ ],
+ [
+ 36,
+ 520000
+ ]
+ ]
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file