From c847e3bf6b822c83fc096104b59755015d7ac1c2 Mon Sep 17 00:00:00 2001 From: Tiago Amorim Date: Sun, 14 Apr 2024 15:54:40 +0100 Subject: [PATCH] replaced GetDailyTransformation logic by GetProduction --- src/db_api/transformations.rs | 54 ++++++++++++++++++++++ src/routes/mod.rs | 86 +++++++++++++++++++++++++++++++++-- src/startup.rs | 2 +- 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/src/db_api/transformations.rs b/src/db_api/transformations.rs index d858fd9..61f0dfb 100644 --- a/src/db_api/transformations.rs +++ b/src/db_api/transformations.rs @@ -66,6 +66,30 @@ impl Transformation { Ok(()) } + pub async fn get_n_next_raw_mat_transf( + n: i64, + con: &mut PgConnection, + ) -> sqlx::Result> { + Ok(sqlx::query!( + r#" + SELECT t.material_id FROM transformations AS t + JOIN items AS i ON t.material_id = i.id + WHERE + (i.piece_kind = 'P1' OR i.piece_kind = 'P2') + AND i.status = 'in_stock' + AND t.status = 'pending' + ORDER BY date + LIMIT $1; + "#, + n + ) + .fetch_all(con) + .await? + .iter() + .map(|row| row.material_id) + .collect()) + } + pub async fn get_by_id( id: i64, con: &mut PgConnection, @@ -146,4 +170,34 @@ impl TransformationDetails { .fetch_all(con) .await } + + pub async fn get_by_id( + id: Uuid, + con: &mut PgConnection, + ) -> sqlx::Result> { + sqlx::query_as!( + TransformationDetails, + r#" + SELECT + + t.id as transformation_id, + t.material_id, + t.product_id, + + recipes.material_kind as "material_kind: PieceKind", + recipes.product_kind as "product_kind: PieceKind", + recipes.tool as "tool: ToolType", + recipes.operation_time + + FROM transformations AS t + + JOIN recipes ON t.recipe_id = recipes.id + + WHERE t.material_id = $1 + "#, + id + ) + .fetch_optional(con) + .await + } } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 2f557e0..04e40d4 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -54,12 +54,85 @@ pub async fn post_date(form: Form) -> impl Responder { match CURRENT_DATE.write() { Ok(mut date) => { *date = form.day; + tracing::info!("Date set to {}", form.day); HttpResponse::Created().finish() } - Err(e) => internal_server_error(e), + Err(e) => panic!("Date lock was poisoned: {:?}", e), } } +#[derive(Debug, Deserialize)] +#[cfg_attr(test, derive(serde::Serialize))] +struct ProductionForm { + max_n_items: u32, +} + +#[derive(Debug, Serialize)] +struct Recipe { + steps: Vec, +} + +#[get("/production")] +pub async fn get_production( + query: Query, + pool: Data, +) -> impl Responder { + let mut tx = match pool.begin().await { + Ok(tx) => tx, + Err(e) => return internal_server_error(e), + }; + + let n_items = query.max_n_items as i64; + let ids = match Transformation::get_n_next_raw_mat_transf(n_items, &mut tx) + .await + { + Ok(ids) => ids, + Err(e) => return internal_server_error(e), + }; + + let mut recipes = Vec::new(); + for material_id in ids { + let mut steps = Vec::new(); + let mut material = material_id; + while let Some(transf) = + match TransformationDetails::get_by_id(material, &mut tx).await { + Ok(t) => t, + Err(e) => return internal_server_error(e), + } + { + material = transf.product_id; + steps.push(transf); + } + recipes.push(Recipe { steps }) + } + + if recipes.iter().any(|r| r.steps.is_empty()) { + tracing::error!("Some transformations are missing"); + return HttpResponse::NotFound().finish(); + } + + for recipe in &recipes { + //NOTE: all items in a recipe relate to the same order + let transf = &recipe.steps[0]; + let order = + match Order::get_by_item_id(transf.product_id, &mut tx).await { + Ok(Some(order)) => order, + Ok(None) => continue, + Err(e) => return internal_server_error(e), + }; + if let Err(e) = order.production_start(&mut tx).await { + return internal_server_error(e); + } + tracing::info!("Started production for order {}", order.id()); + } + + if let Err(e) = tx.commit().await { + return internal_server_error(e); + } + + HttpResponse::Ok().json(recipes) +} + #[get("/transformations")] pub async fn get_daily_transformations( query: Query, @@ -250,12 +323,12 @@ pub async fn post_warehouse_action( #[derive(Debug, Deserialize, Serialize)] struct ExpectedShipmentForm { - shipment_id: i64, + shippment_id: i64, material_type: RawMaterial, quantity: i32, } -#[post("/materials/expected")] +#[get("/materials/expected")] pub async fn get_expected_shippments( query: Query, pool: Data, @@ -271,7 +344,7 @@ pub async fn get_expected_shippments( Ok(shipp_vec) => shipp_vec .iter() .map(|s| ExpectedShipmentForm { - shipment_id: s.id, + shippment_id: s.id, material_type: s.material_type, quantity: s.quantity, }) @@ -296,8 +369,11 @@ pub async fn post_material_arrival( let date = Scheduler::get_date() as i32; match Shippment::arrived(form.shippment_id, date, &pool).await { - Ok(_) => HttpResponse::Created().finish(), Err(e) => internal_server_error(e), + Ok(_) => { + tracing::info!("Shippment {} arrived", form.shippment_id); + HttpResponse::Created().finish() + } } } diff --git a/src/startup.rs b/src/startup.rs index 111ed73..3174a91 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -105,7 +105,7 @@ impl App { .service(routes::check_health) .service(routes::get_date) .service(routes::post_date) - .service(routes::get_daily_transformations) + .service(routes::get_production) .service(routes::post_transformation_completion) .service(routes::post_warehouse_action) .service(routes::get_expected_shippments)