diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bca4531b..4dd723d0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Fixed bug where `Lithostratigraphhy Top Bedrock` and `Chronostratigraphhy Top Bedrock` were not displayed in form after updating them and navigating away. - Ensure all hydrotest codelist values are imported. - JSON export/import did not handle borehole geometry and location geometry correctly. +- JSON import did not handle casing references of observations, backfills and instrumentations correctly. - In some cases, the color of the workflow badge did not match the publication status. ## v2.1.993 - 2024-12-13 diff --git a/src/api/Controllers/ImportController.cs b/src/api/Controllers/ImportController.cs index 7a82434ce..fe72fcbf3 100644 --- a/src/api/Controllers/ImportController.cs +++ b/src/api/Controllers/ImportController.cs @@ -94,6 +94,8 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF borehole.UpdatedBy = null; borehole.CreatedBy = null; + MapCasingReferences(borehole); + borehole.Stratigraphies?.MarkAsNew(); borehole.Completions?.MarkAsNew(); borehole.Sections?.MarkAsNew(); @@ -265,6 +267,20 @@ private async Task> GetHydrotestCodelistsAsync() .ConfigureAwait(false); } + private static void MapCasingReferences(BoreholeImport borehole) + { + var casings = borehole.Completions?.SelectMany(c => c.Casings ?? Enumerable.Empty()).ToDictionary(c => c.Id); + if (casings == null) return; + + borehole.Observations?.MapCasings(casings); + + foreach (var completion in borehole.Completions) + { + completion.Instrumentations?.MapCasings(casings); + completion.Backfills?.MapCasings(casings); + } + } + private static void MapHydrotestCodelists(BoreholeImport borehole, List hydrotestCodelists) { var hydroTests = borehole.Observations?.OfType().ToList(); @@ -305,6 +321,7 @@ private void ValidateBorehole(BoreholeImport borehole, List bore ValidateRequiredFields(borehole, boreholeIndex, isJsonFile); ValidateDuplicateInFile(borehole, boreholesFromFile, boreholeIndex, isJsonFile); ValidateDuplicateInDb(borehole, workgroupId, boreholeIndex, isJsonFile); + ValidateCasingReferences(borehole, boreholeIndex); } private void ValidateRequiredFields(BoreholeImport borehole, int processingIndex, bool isJsonFile) @@ -344,6 +361,30 @@ private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int } } + private void ValidateCasingReferences(BoreholeImport borehole, int processingIndex) + { + // Get all casing Ids from the borehole's completions + var casingIds = borehole.Completions? + .SelectMany(c => c.Casings ?? Enumerable.Empty()) + .Select(c => c.Id) + .ToHashSet() ?? new HashSet(); + + // Aggregate all CasingId references from Observations, Instrumentations, and Backfills + var casingReferenceIdsInBorehole = new HashSet(borehole.Observations?.Where(o => o.CasingId.HasValue).Select(o => o.CasingId!.Value) ?? []); + casingReferenceIdsInBorehole + .UnionWith(borehole.Completions?.SelectMany(c => c.Instrumentations ?? Enumerable.Empty()) + .Where(i => i.CasingId.HasValue) + .Select(i => i.CasingId!.Value) ?? []); + casingReferenceIdsInBorehole + .UnionWith(borehole.Completions?.SelectMany(c => c.Backfills ?? Enumerable.Empty()) + .Where(b => b.CasingId.HasValue) + .Select(b => b.CasingId!.Value) ?? []); + + // Check if any referenced CasingId is not found in the casingIds set + var invalidReferences = casingReferenceIdsInBorehole.Except(casingIds).ToList(); + if (invalidReferences.Count > 0) AddValidationErrorToModelState(processingIndex, $"Some {nameof(ICasingReference.CasingId)} in {nameof(Borehole.Observations)}/{nameof(Completion.Backfills)}/{nameof(Completion.Instrumentations)} do not exist in the borehole's casings.", true); + } + internal static bool CompareValuesWithTolerance(double? firstValue, double? secondValue, double tolerance) { if (firstValue == null && secondValue == null) return true; diff --git a/src/api/Models/Backfill.cs b/src/api/Models/Backfill.cs index 42c95f66c..b0e3d17eb 100644 --- a/src/api/Models/Backfill.cs +++ b/src/api/Models/Backfill.cs @@ -7,7 +7,7 @@ namespace BDMS.Models; /// Represents a Backfill entity in the database. /// [Table("backfill")] -public class Backfill : IChangeTracking, IIdentifyable +public class Backfill : IChangeTracking, IIdentifyable, ICasingReference { /// [Column("id")] diff --git a/src/api/Models/ICasingReference.cs b/src/api/Models/ICasingReference.cs new file mode 100644 index 000000000..fba07cfa5 --- /dev/null +++ b/src/api/Models/ICasingReference.cs @@ -0,0 +1,17 @@ +namespace BDMS.Models; + +/// +/// An object that has a reference to a . +/// +public interface ICasingReference +{ + /// + /// Gets or sets the ID of the casing in the join table. + /// + int? CasingId { get; set; } + + /// + /// Gets or sets the casing in the join table. + /// + Casing? Casing { get; set; } +} diff --git a/src/api/Models/ICasingReferenceExtensions.cs b/src/api/Models/ICasingReferenceExtensions.cs new file mode 100644 index 000000000..0d05697ae --- /dev/null +++ b/src/api/Models/ICasingReferenceExtensions.cs @@ -0,0 +1,38 @@ +namespace BDMS.Models; + +internal static class ICasingReferenceExtensions +{ + /// + /// Maps a single ICasingReference to its corresponding Casing from the dictionary. + /// + public static void MapCasing(this ICasingReference casingReference, Dictionary casings) + { + if (casingReference == null) return; + + casingReference.Casing = null; + if (casingReference.CasingId.HasValue) + { + if (casings.TryGetValue(casingReference.CasingId.Value, out var casing)) + { + casingReference.Casing = casing; + } + else + { + throw new InvalidOperationException($"Casing with ID {casingReference.CasingId} not found."); + } + } + } + + /// + /// Maps a list of ICasingReference objects to their corresponding Casings from the dictionary. + /// + public static void MapCasings(this IEnumerable casingReferences, Dictionary casings) + { + if (casingReferences == null) return; + + foreach (var casingReference in casingReferences) + { + casingReference.MapCasing(casings); + } + } +} diff --git a/src/api/Models/Instrumentation.cs b/src/api/Models/Instrumentation.cs index 1f4712462..87b18b691 100644 --- a/src/api/Models/Instrumentation.cs +++ b/src/api/Models/Instrumentation.cs @@ -7,7 +7,7 @@ namespace BDMS.Models; /// Represents a Instrumentation entity in the database. /// [Table("instrumentation")] -public class Instrumentation : IChangeTracking, IIdentifyable +public class Instrumentation : IChangeTracking, IIdentifyable, ICasingReference { /// [Column("id")] diff --git a/src/api/Models/Observation.cs b/src/api/Models/Observation.cs index 7e1e362a0..56dd94082 100644 --- a/src/api/Models/Observation.cs +++ b/src/api/Models/Observation.cs @@ -8,7 +8,7 @@ namespace BDMS.Models; /// Represents an observation in the boring process. /// [Table("observation")] -public class Observation : IChangeTracking, IIdentifyable +public class Observation : IChangeTracking, IIdentifyable, ICasingReference { /// /// Gets or sets the 's id. diff --git a/tests/api/BDMS.Test.csproj b/tests/api/BDMS.Test.csproj index d7eb31780..85f6c0922 100644 --- a/tests/api/BDMS.Test.csproj +++ b/tests/api/BDMS.Test.csproj @@ -71,6 +71,9 @@ Always + + Always + Always diff --git a/tests/api/Controllers/ImportControllerTest.cs b/tests/api/Controllers/ImportControllerTest.cs index 8e4f4f2a1..44482d214 100644 --- a/tests/api/Controllers/ImportControllerTest.cs +++ b/tests/api/Controllers/ImportControllerTest.cs @@ -310,6 +310,15 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.AreEqual("Ratione ut non in recusandae labore.", completion.Notes, nameof(completion.Notes)); Assert.AreEqual(DateOnly.Parse("2021-01-24", CultureInfo.InvariantCulture), completion.AbandonDate, nameof(completion.AbandonDate)); + // Assert casing ids of instrumentations, backfills and observations + var casingIds = borehole.Completions.Where(c => c.Casings != null).SelectMany(c => c.Casings!).Select(c => c.Id).ToList(); + var instrumentationCasingIds = borehole.Completions.Where(c => c.Instrumentations != null).SelectMany(c => c.Instrumentations!).Where(i => i.CasingId.HasValue).Select(i => (int)i.CasingId).ToList(); + var backfillCasingIds = borehole.Completions.Where(c => c.Backfills != null).SelectMany(c => c.Backfills!).Where(i => i.CasingId.HasValue).Select(i => (int)i.CasingId).ToList(); + var observationCasingIds = borehole.Observations.Where(i => i.CasingId.HasValue).Select(i => (int)i.CasingId).ToList(); + Assert.IsTrue(instrumentationCasingIds.All(c => casingIds.Contains(c)), $"{nameof(instrumentationCasingIds)} in {nameof(casingIds)}"); + Assert.IsTrue(backfillCasingIds.All(c => casingIds.Contains(c)), $"{nameof(backfillCasingIds)} in {nameof(casingIds)}"); + Assert.IsTrue(observationCasingIds.All(c => casingIds.Contains(c)), $"{nameof(observationCasingIds)} in {nameof(casingIds)}"); + // Assert completion's instrumentations Assert.AreEqual(1, completion.Instrumentations.Count, nameof(completion.Instrumentations.Count)); var instrumentation = completion.Instrumentations.First(); @@ -326,7 +335,6 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.AreEqual(25000213, instrumentation.StatusId, nameof(instrumentation.StatusId)); Assert.IsNull(instrumentation.Status, nameof(instrumentation.Status).ShouldBeNullMessage()); Assert.IsFalse(instrumentation.IsOpenBorehole, nameof(instrumentation.IsOpenBorehole)); - Assert.AreEqual(17000312, instrumentation.CasingId, nameof(instrumentation.CasingId)); Assert.IsNotNull(instrumentation.Casing, nameof(instrumentation.Casing).ShouldNotBeNullMessage()); Assert.AreEqual("copy Field bandwidth Burg", instrumentation.Notes, nameof(instrumentation.Notes)); @@ -345,7 +353,6 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.AreEqual(25000306, backfill.MaterialId, nameof(backfill.MaterialId)); Assert.IsNull(backfill.Material, nameof(backfill.Material).ShouldBeNullMessage()); Assert.IsFalse(backfill.IsOpenBorehole, nameof(backfill.IsOpenBorehole)); - Assert.AreEqual(17000011, backfill.CasingId, nameof(backfill.CasingId)); Assert.IsNotNull(backfill.Casing, nameof(backfill.Casing).ShouldNotBeNullMessage()); Assert.AreEqual("Licensed Plastic Soap Managed withdrawal Tools & Industrial", backfill.Notes, nameof(backfill.Notes)); @@ -486,6 +493,25 @@ public async Task UploadJsonWithNoJsonFileShouldReturnError() Assert.AreEqual("Invalid or empty file uploaded.", badRequestResult.Value); } + [TestMethod] + public async Task UploadJsonWithInvalidCasingIdsShouldReturnError() + { + var boreholeJsonFile = GetFormFileByExistingFile("json_import_invalid_casing_ids.json"); + + ActionResult response = await controller.UploadJsonFileAsync(workgroupId: 1, boreholeJsonFile); + + Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); + ObjectResult result = (ObjectResult)response.Result!; + ActionResultAssert.IsBadRequest(result); + + ValidationProblemDetails problemDetails = (ValidationProblemDetails)result.Value!; + Assert.AreEqual(3, problemDetails.Errors.Count); + + CollectionAssert.AreEquivalent(new[] { $"Some {nameof(ICasingReference.CasingId)} in {nameof(Borehole.Observations)}/{nameof(Completion.Backfills)}/{nameof(Completion.Instrumentations)} do not exist in the borehole's casings.", }, problemDetails.Errors["Borehole0"]); + CollectionAssert.AreEquivalent(new[] { $"Some {nameof(ICasingReference.CasingId)} in {nameof(Borehole.Observations)}/{nameof(Completion.Backfills)}/{nameof(Completion.Instrumentations)} do not exist in the borehole's casings.", }, problemDetails.Errors["Borehole1"]); + CollectionAssert.AreEquivalent(new[] { $"Some {nameof(ICasingReference.CasingId)} in {nameof(Borehole.Observations)}/{nameof(Completion.Backfills)}/{nameof(Completion.Instrumentations)} do not exist in the borehole's casings.", }, problemDetails.Errors["Borehole2"]); + } + [TestMethod] public async Task UploadJsonWithDuplicateBoreholesByLocationShouldReturnError() { diff --git a/tests/api/TestData/json_import_duplicated_by_location.json b/tests/api/TestData/json_import_duplicated_by_location.json index dc6f47dcf..e09db5b92 100644 --- a/tests/api/TestData/json_import_duplicated_by_location.json +++ b/tests/api/TestData/json_import_duplicated_by_location.json @@ -715,7 +715,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000312, + "casingId": null, "casing": null, "notes": "copy Field bandwidth Burg", "createdById": 5, @@ -738,7 +738,7 @@ "materialId": 25000306, "material": null, "isOpenBorehole": false, - "casingId": 17000011, + "casingId": null, "casing": null, "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", "createdById": 2, @@ -839,7 +839,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000282, + "casingId": null, "casing": null, "notes": "monitor alarm Fresh SSL", "createdById": 2, @@ -862,7 +862,7 @@ "materialId": 25000310, "material": null, "isOpenBorehole": false, - "casingId": 17000421, + "casingId": null, "casing": null, "notes": "Handmade Soft Fish Checking Account transmitting salmon", "createdById": 1, @@ -1086,7 +1086,7 @@ "toDepthM": 2227.610979433456, "fromDepthMasl": 3136.3928836828063, "toDepthMasl": 4047.543691819787, - "casingId": 17000130, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Quis repellendus nihil et ipsam ut ad eius.", @@ -1111,7 +1111,7 @@ "toDepthM": 759.5223660401639, "fromDepthMasl": 4940.758798705768, "toDepthMasl": 587.5749591791886, - "casingId": 17000495, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", @@ -1873,7 +1873,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000312, + "casingId": null, "casing": null, "notes": "copy Field bandwidth Burg", "createdById": 5, @@ -1896,7 +1896,7 @@ "materialId": 25000306, "material": null, "isOpenBorehole": false, - "casingId": 17000011, + "casingId": null, "casing": null, "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", "createdById": 2, @@ -1997,7 +1997,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000282, + "casingId": null, "casing": null, "notes": "monitor alarm Fresh SSL", "createdById": 2, @@ -2020,7 +2020,7 @@ "materialId": 25000310, "material": null, "isOpenBorehole": false, - "casingId": 17000421, + "casingId": null, "casing": null, "notes": "Handmade Soft Fish Checking Account transmitting salmon", "createdById": 1, @@ -2244,7 +2244,7 @@ "toDepthM": 2227.610979433456, "fromDepthMasl": 3136.3928836828063, "toDepthMasl": 4047.543691819787, - "casingId": 17000130, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Quis repellendus nihil et ipsam ut ad eius.", @@ -2269,7 +2269,7 @@ "toDepthM": 759.5223660401639, "fromDepthMasl": 4940.758798705768, "toDepthMasl": 587.5749591791886, - "casingId": 17000495, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", diff --git a/tests/api/TestData/json_import_duplicates_existing.json b/tests/api/TestData/json_import_duplicates_existing.json index 1d5aab43b..0db1b24a4 100644 --- a/tests/api/TestData/json_import_duplicates_existing.json +++ b/tests/api/TestData/json_import_duplicates_existing.json @@ -715,7 +715,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000312, + "casingId": null, "casing": null, "notes": "copy Field bandwidth Burg", "createdById": 5, @@ -738,7 +738,7 @@ "materialId": 25000306, "material": null, "isOpenBorehole": false, - "casingId": 17000011, + "casingId": null, "casing": null, "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", "createdById": 2, @@ -839,7 +839,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000282, + "casingId": null, "casing": null, "notes": "monitor alarm Fresh SSL", "createdById": 2, @@ -862,7 +862,7 @@ "materialId": 25000310, "material": null, "isOpenBorehole": false, - "casingId": 17000421, + "casingId": null, "casing": null, "notes": "Handmade Soft Fish Checking Account transmitting salmon", "createdById": 1, @@ -1086,7 +1086,7 @@ "toDepthM": 2227.610979433456, "fromDepthMasl": 3136.3928836828063, "toDepthMasl": 4047.543691819787, - "casingId": 17000130, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Quis repellendus nihil et ipsam ut ad eius.", @@ -1111,7 +1111,7 @@ "toDepthM": 759.5223660401639, "fromDepthMasl": 4940.758798705768, "toDepthMasl": 587.5749591791886, - "casingId": 17000495, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", @@ -1873,7 +1873,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000312, + "casingId": null, "casing": null, "notes": "copy Field bandwidth Burg", "createdById": 5, @@ -1896,7 +1896,7 @@ "materialId": 25000306, "material": null, "isOpenBorehole": false, - "casingId": 17000011, + "casingId": null, "casing": null, "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", "createdById": 2, @@ -1997,7 +1997,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000282, + "casingId": null, "casing": null, "notes": "monitor alarm Fresh SSL", "createdById": 2, @@ -2020,7 +2020,7 @@ "materialId": 25000310, "material": null, "isOpenBorehole": false, - "casingId": 17000421, + "casingId": null, "casing": null, "notes": "Handmade Soft Fish Checking Account transmitting salmon", "createdById": 1, @@ -2244,7 +2244,7 @@ "toDepthM": 2227.610979433456, "fromDepthMasl": 3136.3928836828063, "toDepthMasl": 4047.543691819787, - "casingId": 17000130, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Quis repellendus nihil et ipsam ut ad eius.", @@ -2269,7 +2269,7 @@ "toDepthM": 759.5223660401639, "fromDepthMasl": 4940.758798705768, "toDepthMasl": 587.5749591791886, - "casingId": 17000495, + "casingId": null, "isOpenBorehole": true, "casing": null, "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", diff --git a/tests/api/TestData/json_import_invalid_casing_ids.json b/tests/api/TestData/json_import_invalid_casing_ids.json new file mode 100644 index 000000000..56ce632e4 --- /dev/null +++ b/tests/api/TestData/json_import_invalid_casing_ids.json @@ -0,0 +1,246 @@ +[ + { + "id": 2000001, + "createdById": 2, + "created": "2022-01-12T10:15:30.000Z", + "updated": "2022-01-15T12:00:00.000Z", + "updatedById": 3, + "lockedById": 4, + "workgroupId": 2, + "isPublic": false, + "locationX": 2800000, + "precisionLocationX": 5, + "locationY": 1350000, + "precisionLocationY": 5, + "elevationZ": 3200.0, + "totalDepth": 600.0, + "originalName": "INSTRUMENTATION_BOREHOLE", + "name": "BOREHOLE_A", + "hasGroundwater": true, + "Geometry": { + "type": "Point", + "coordinates": [ 2800000, 1350000 ] + }, + "completions": [ + { + "id": 14000001, + "boreholeId": 2000001, + "isPrimary": true, + "name": "Completion A", + "casings": [ + { + "id": 10, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial" + } + ], + "instrumentations": [ + { + "id": 15000001, + "completionId": 14000001, + "fromDepth": 50, + "toDepth": 100, + "name": "Instrumentation A", + "casingId": 0, + "notes": "Instrumentation details for borehole with casing ID 0." + }, + { + "id": 15000002, + "completionId": 14000001, + "fromDepth": 50, + "toDepth": 100, + "name": "Instrumentation A", + "casingId": null + } + ], + "backfills": [] + } + ], + "observations": [] + }, + { + "id": 2000002, + "createdById": 5, + "created": "2023-03-05T08:30:45.000Z", + "updated": "2023-03-07T11:45:00.000Z", + "updatedById": 6, + "lockedById": 7, + "workgroupId": 3, + "isPublic": true, + "locationX": 2850000, + "precisionLocationX": 6, + "locationY": 1400000, + "precisionLocationY": 6, + "elevationZ": 3100.0, + "totalDepth": 700.0, + "originalName": "BACKFILLS_BOREHOLE", + "name": "BOREHOLE_B", + "hasGroundwater": false, + "Geometry": { + "type": "Point", + "coordinates": [ 2850000, 1400000 ] + }, + "completions": [ + { + "id": 14000002, + "boreholeId": 2000002, + "isPrimary": false, + "name": "Completion B", + "casings": [ + { + "id": 10, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial" + } + ], + "backfills": [ + { + "id": 16000001, + "completionId": 14000002, + "fromDepth": 30, + "toDepth": 60, + "casingId": 0, + "notes": "Backfill details for borehole with casing ID 0." + }, + { + "id": 16000002, + "completionId": 14000002, + "fromDepth": 30, + "toDepth": 60, + "casingId": null + } + ], + "instrumentations": [], + "observations": [] + } + ], + "observations": [] + }, + { + "id": 2000003, + "createdById": 8, + "created": "2024-04-10T09:45:20.000Z", + "updated": "2024-04-12T13:15:10.000Z", + "updatedById": 9, + "lockedById": 10, + "workgroupId": 4, + "isPublic": true, + "locationX": 2900000, + "precisionLocationX": 7, + "locationY": 1450000, + "precisionLocationY": 7, + "elevationZ": 3000.0, + "totalDepth": 800.0, + "originalName": "OBSERVATIONS_BOREHOLE", + "name": "BOREHOLE_C", + "hasGroundwater": true, + "Geometry": { + "type": "Point", + "coordinates": [ 2900000, 1450000 ] + }, + "completions": [ + { + "id": 14000003, + "boreholeId": 2000003, + "isPrimary": true, + "name": "Completion C", + "casings": [ + { + "id": 10, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial" + } + ], + "instrumentations": [], + "backfills": [] + } + ], + "observations": [ + { + "id": 12000001, + "fromDepthM": 100, + "toDepthM": 200, + "casingId": 0, + "comment": "Observation details for borehole with casing ID 0." + }, + { + "id": 12000002, + "fromDepthM": 100, + "toDepthM": 200, + "casingId": null + } + ] + }, + { + "id": 2000004, + "createdById": 11, + "created": "2025-01-01T10:00:00.000Z", + "updated": "2025-01-03T14:30:00.000Z", + "updatedById": 12, + "lockedById": 13, + "workgroupId": 5, + "isPublic": false, + "locationX": 2950000, + "precisionLocationX": 5, + "locationY": 1500000, + "precisionLocationY": 5, + "elevationZ": 2900.0, + "totalDepth": 900.0, + "originalName": "NO_COMPLETIONS_BOREHOLE", + "name": "BOREHOLE_D", + "hasGroundwater": false, + "Geometry": { + "type": "Point", + "coordinates": [ 2950000, 1500000 ] + }, + "completions": [], + "observations": [] + }, + { + "id": 2000005, + "createdById": 14, + "created": "2025-02-10T08:45:30.000Z", + "updated": "2025-02-12T11:15:00.000Z", + "updatedById": 15, + "lockedById": 16, + "workgroupId": 6, + "isPublic": true, + "locationX": 3000000, + "precisionLocationX": 6, + "locationY": 1550000, + "precisionLocationY": 6, + "elevationZ": 2800.0, + "totalDepth": 950.0, + "originalName": "NO_CASINGS_BOREHOLE", + "name": "BOREHOLE_E", + "hasGroundwater": true, + "Geometry": { + "type": "Point", + "coordinates": [ 3000000, 1550000 ] + }, + "completions": [ + { + "id": 14000005, + "boreholeId": 2000005, + "isPrimary": false, + "name": "Completion E", + "casings": [], + "instrumentations": [], + "backfills": [] + } + ], + "observations": [] + } +] diff --git a/tests/api/TestData/json_import_valid.json b/tests/api/TestData/json_import_valid.json index 4d67739f7..85d717787 100644 --- a/tests/api/TestData/json_import_valid.json +++ b/tests/api/TestData/json_import_valid.json @@ -769,7 +769,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000312, + "casingId": 17000377, "casing": null, "notes": "copy Field bandwidth Burg", "createdById": 5, @@ -792,7 +792,7 @@ "materialId": 25000306, "material": null, "isOpenBorehole": false, - "casingId": 17000011, + "casingId": 17000377, "casing": null, "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", "createdById": 2, @@ -893,7 +893,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000282, + "casingId": 17000377, "casing": null, "notes": "monitor alarm Fresh SSL", "createdById": 2, @@ -916,7 +916,7 @@ "materialId": 25000310, "material": null, "isOpenBorehole": false, - "casingId": 17000421, + "casingId": 17000377, "casing": null, "notes": "Handmade Soft Fish Checking Account transmitting salmon", "createdById": 1, @@ -1158,7 +1158,7 @@ "toDepthM": 2227.610979433456, "fromDepthMasl": 3136.3928836828063, "toDepthMasl": 4047.543691819787, - "casingId": 17000130, + "casingId": 17000377, "isOpenBorehole": true, "casing": null, "comment": "Quis repellendus nihil et ipsam ut ad eius.", @@ -1183,7 +1183,7 @@ "toDepthM": 759.5223660401639, "fromDepthMasl": 4940.758798705768, "toDepthMasl": 587.5749591791886, - "casingId": 17000495, + "casingId": 17000377, "isOpenBorehole": true, "casing": null, "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", @@ -2133,7 +2133,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000312, + "casingId": 17000011, "casing": null, "notes": "copy Field bandwidth Burg", "createdById": 5, @@ -2156,7 +2156,7 @@ "materialId": 25000306, "material": null, "isOpenBorehole": false, - "casingId": 17000011, + "casingId": 17000326, "casing": null, "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", "createdById": 2, @@ -2169,7 +2169,7 @@ ], "casings": [ { - "id": 17000377, + "id": 17000011, "completionId": 14000039, "completion": null, "name": "Rustic", @@ -2257,7 +2257,7 @@ "statusId": 25000213, "status": null, "isOpenBorehole": false, - "casingId": 17000282, + "casingId": 17000326, "casing": null, "notes": "monitor alarm Fresh SSL", "createdById": 2, @@ -2280,7 +2280,7 @@ "materialId": 25000310, "material": null, "isOpenBorehole": false, - "casingId": 17000421, + "casingId": 17000011, "casing": null, "notes": "Handmade Soft Fish Checking Account transmitting salmon", "createdById": 1, @@ -2504,7 +2504,7 @@ "toDepthM": 2227.610979433456, "fromDepthMasl": 3136.3928836828063, "toDepthMasl": 4047.543691819787, - "casingId": 17000130, + "casingId": 17000011, "isOpenBorehole": true, "casing": null, "comment": "Quis repellendus nihil et ipsam ut ad eius.", @@ -2529,7 +2529,7 @@ "toDepthM": 759.5223660401639, "fromDepthMasl": 4940.758798705768, "toDepthMasl": 587.5749591791886, - "casingId": 17000495, + "casingId": 17000326, "isOpenBorehole": true, "casing": null, "comment": "Ut et accusamus praesentium consequuntur nulla dolor.",