164 lines
6.3 KiB
Rust
164 lines
6.3 KiB
Rust
use fathom_function::{chrono::NaiveDate, forms::deserialize_date, tracing};
|
|
use pipeline_application::{
|
|
application::{
|
|
Application, FieldAssessment, PurposeOfMeasurement, SurfaceLocation,
|
|
features::{FeatureIdentification, FeatureType},
|
|
orientation::Orientation,
|
|
},
|
|
serialization::{serialize_meter, serialize_millimeter},
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_this_or_that::as_opt_u64;
|
|
use uom::si::f64::Length;
|
|
use uuid::Uuid;
|
|
|
|
#[fathom_function::function]
|
|
async fn upload_field_assessment(input: Input) -> Result<Output, String> {
|
|
let app = Application::new_from_compile_env(input.org_id, input.project_id).unwrap();
|
|
|
|
for pipeline_id in input.pipeline_id {
|
|
app.upload_field_assessment(pipeline_id, &input.report)
|
|
.await
|
|
.map_err(|err| {
|
|
tracing::error!(%pipeline_id, ?err, "Error uploading field assessment");
|
|
format!("{err:?}")
|
|
})?;
|
|
}
|
|
|
|
Ok(Output {
|
|
status: "Success".to_owned(),
|
|
})
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
struct Output {
|
|
status: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct Input {
|
|
org_id: Uuid,
|
|
project_id: String,
|
|
pipeline_id: Vec<Uuid>,
|
|
#[serde(flatten)]
|
|
report: Report,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct Report {
|
|
/// The date of this field inspection.
|
|
#[serde(deserialize_with = "deserialize_date")]
|
|
date: NaiveDate,
|
|
/// The log distance: the absolute distance measured in meters from the launcher.
|
|
#[serde(with = "serialize_meter")]
|
|
log_distance: Length,
|
|
|
|
/// The Girthweld number. These follow a sequential order of 10 (e.g., 10, 20, 30, ...) to
|
|
/// enumerate each joint from the initial to the final one. This ordering system facilitates
|
|
/// future repairs using the "Pipeline Sectional Replacement" method.
|
|
#[serde(deserialize_with = "as_opt_u64")]
|
|
girth_weld: Option<u64>,
|
|
|
|
/// The circumferential position of the starting point of an anomaly, specifically the top-left
|
|
/// position on the pipe.
|
|
///
|
|
/// This orientation is measured in O'clock notation, ranging from 00:00 to 12:00, indicating
|
|
/// the position around the circumference of the pipe. This is the number of hours
|
|
#[serde(deserialize_with = "as_opt_u64")]
|
|
anomaly_orientation_hours: Option<u64>,
|
|
|
|
/// The circumferential position of the starting point of an anomaly, specifically the top-left
|
|
/// position on the pipe.
|
|
///
|
|
/// This orientation is measured in O'clock notation, ranging from 00:00 to 12:00, indicating
|
|
/// the position around the circumference of the pipe. This is the number of minutes
|
|
#[serde(deserialize_with = "as_opt_u64")]
|
|
anomaly_orientation_minutes: Option<u64>,
|
|
|
|
/// The measured wall thickness of the pipeline taken from an un-corroded location. Corresponds
|
|
/// to the un-corroded wall thickness.
|
|
#[serde(with = "serialize_millimeter::opt")]
|
|
measured_wall_thickness: Option<Length>,
|
|
|
|
/// The measured wall thickness of the pipeline taken from the river bottom of the corrosion.
|
|
#[serde(with = "serialize_millimeter::opt")]
|
|
measured_remaining_wall_thickness: Option<Length>,
|
|
|
|
/// The surface location of the anomaly.
|
|
///
|
|
/// Each identified anomaly, denoted as ANOM, falls into one of four categories: Internal
|
|
/// (INT), External (EXT), Midwall (MID), or Unknown (UNK) for any reason. These
|
|
/// classifications are assigned based on the specific characteristics and location of the
|
|
/// anomaly on the pipeline. The categorization helps provide a comprehensive understanding of
|
|
/// the nature of the anomalies present.
|
|
surface_location: Option<SurfaceLocation>,
|
|
|
|
/// The measured length (in mm) of an anomaly, (the length of the corrosion box) in relation to
|
|
/// the reporting threshold.
|
|
#[serde(with = "serialize_millimeter")]
|
|
measured_length: Length,
|
|
|
|
/// The circumferential width of an anomaly, this denotes the measured measurement of the
|
|
/// anomaly's width in circumferential direction, comparable to the width of the corrosion box,
|
|
/// concerning the reporting threshold and the unit is mm.
|
|
#[serde(with = "serialize_millimeter::opt")]
|
|
measured_width: Option<Length>,
|
|
|
|
/// The measured depth of the anomaly.
|
|
///
|
|
/// This measurement is essential for evaluating the structural integrity of the pipeline. A
|
|
/// higher percentage of metal loss indicates a more significant impact on the pipeline's
|
|
/// strength and durability.
|
|
#[serde(with = "serialize_millimeter")]
|
|
measured_max_depth: Length,
|
|
|
|
/// The reason for this field assessment
|
|
purpose_of_measurement: PurposeOfMeasurement,
|
|
|
|
/// The accuracy of the tool used
|
|
#[serde(with = "serialize_millimeter::opt")]
|
|
tool_accuracy: Option<Length>,
|
|
|
|
/// The accuracy of the pit gauge used
|
|
#[serde(with = "serialize_millimeter::opt")]
|
|
pit_gauge_accuracy: Option<Length>,
|
|
|
|
/// The inspector name or identifier
|
|
inspector: String,
|
|
/// And additional remarks about the inspection
|
|
remarks: Option<String>,
|
|
}
|
|
|
|
impl Report {
|
|
fn orientation(&self) -> Option<Orientation> {
|
|
Some(Orientation::new(
|
|
self.anomaly_orientation_hours? as _,
|
|
self.anomaly_orientation_minutes? as _,
|
|
))
|
|
}
|
|
}
|
|
|
|
impl From<&Report> for FieldAssessment {
|
|
fn from(value: &Report) -> Self {
|
|
Self {
|
|
date: value.date.and_time(Default::default()).and_utc(),
|
|
log_distance: value.log_distance,
|
|
feature_type: Some(FeatureType::ANOM),
|
|
feature_identification: Some(FeatureIdentification::CORR),
|
|
girth_weld: value.girth_weld.map(|v| v as _),
|
|
anomaly_orientation: value.orientation(),
|
|
measured_wall_thickness: value.measured_wall_thickness,
|
|
measured_remaining_wall_thickness: value.measured_remaining_wall_thickness,
|
|
surface_location: value.surface_location,
|
|
measured_length: value.measured_length,
|
|
measured_width: value.measured_width,
|
|
measured_max_depth: value.measured_max_depth,
|
|
purpose_of_measurement: value.purpose_of_measurement.to_owned(),
|
|
tool_accuracy: value.tool_accuracy,
|
|
pit_gauge_accuracy: value.pit_gauge_accuracy,
|
|
inspector: value.inspector.to_owned(),
|
|
remarks: value.remarks.to_owned(),
|
|
}
|
|
}
|
|
}
|