diff --git a/backend/migrations/20260623204328_ingredients.up.sql b/backend/migrations/20260623204328_ingredients.up.sql index 8906ef5..5c99381 100644 --- a/backend/migrations/20260623204328_ingredients.up.sql +++ b/backend/migrations/20260623204328_ingredients.up.sql @@ -16,7 +16,6 @@ CREATE TABLE ingredients ( supplier UUID REFERENCES suppliers(id) NOT NULL, date_recieved TIMESTAMPTZ NOT NULL DEFAULT now(), date_opened TIMESTAMPTZ, - date_last_used TIMESTAMPTZ, - finished BOOLEAN NOT NULL DEFAULT false, + date_finished TIMESTAMPTZ, lot VARCHAR NOT NULL ); diff --git a/backend/migrations/20260623210120_orders.up.sql b/backend/migrations/20260623210120_orders.up.sql index b78b1d2..4aface3 100644 --- a/backend/migrations/20260623210120_orders.up.sql +++ b/backend/migrations/20260623210120_orders.up.sql @@ -1,7 +1,8 @@ -- Add up migration script here CREATE TABLE orders ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - invoice_number VARCHAR NOT NULL + invoice_number VARCHAR NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE order_items ( diff --git a/backend/src/models/ingredient.rs b/backend/src/models/ingredient.rs index cb4a75d..996a31b 100644 --- a/backend/src/models/ingredient.rs +++ b/backend/src/models/ingredient.rs @@ -76,8 +76,7 @@ pub struct Ingredient { pub supplier: Uuid, pub date_recieved: DateTime, pub date_opened: Option>, - pub date_last_used: Option>, - pub finished: bool, + pub date_finished: Option>, pub lot: String, } @@ -87,8 +86,7 @@ pub struct IngredientUpdate { supplier: Option, date_recieved: Option>, date_opened: Option>>, - date_last_used: Option>>, - finished: Option, + date_finished: Option>>, lot: Option, } @@ -98,8 +96,7 @@ pub struct IngredientCreate { supplier: Uuid, date_recieved: DateTime, date_opened: Option>, - date_last_used: Option>, - finished: bool, + date_finished: Option>, lot: String, } @@ -110,16 +107,14 @@ impl Update for IngredientUpdate { supplier, date_recieved, date_opened, - date_last_used, - finished, + date_finished, lot, } = self; ingredient_type.apply_to(&mut other.ingredient_type) | supplier.apply_to(&mut other.supplier) | date_recieved.apply_to(&mut other.date_recieved) | date_opened.apply_to(&mut other.date_opened) - | date_last_used.apply_to(&mut other.date_last_used) - | finished.apply_to(&mut other.finished) + | date_finished.apply_to(&mut other.date_finished) | lot.apply_to(&mut other.lot) } } diff --git a/backend/src/models/order.rs b/backend/src/models/order.rs index 0928325..a72c706 100644 --- a/backend/src/models/order.rs +++ b/backend/src/models/order.rs @@ -10,6 +10,7 @@ pub struct Order { pub id: Uuid, pub invoice_number: String, pub customer_id: Uuid, + pub created_at: chrono::DateTime, } #[derive(Debug, Deserialize, Serialize)] diff --git a/backend/src/routes/batch.rs b/backend/src/routes/batch.rs index e093e40..21e4fbd 100644 --- a/backend/src/routes/batch.rs +++ b/backend/src/routes/batch.rs @@ -24,6 +24,8 @@ struct QueryParams { pub sort_order: Option, pub before: Option>, pub after: Option>, + pub flavor: Option, + pub lot: Option, } #[actix_web::post("")] @@ -61,12 +63,23 @@ async fn get_all(pool: Data, options: Query, user: User) -> if let Some(after) = options.after { query.push(" AND created_at > "); - query.push_bind(after); // safe bind, no injection risk + query.push_bind(after); } if let Some(before) = options.before { query.push(" AND created_at < "); query.push_bind(before); } + if let Some(flavor) = options.flavor { + query.push(" AND flavor_id = "); + query.push_bind(flavor); + } + if let Some(lot) = &options.lot { + if !lot.is_empty() { + query.push(" AND name ILIKE "); + query.push_bind(format!("%{}%", lot)); + query.push(" ESCAPE '\\'"); + } + } query.push(" ORDER BY created_at "); if sort_asc { diff --git a/backend/src/routes/customer.rs b/backend/src/routes/customer.rs index ee1124c..2ca0e18 100644 --- a/backend/src/routes/customer.rs +++ b/backend/src/routes/customer.rs @@ -21,6 +21,7 @@ struct QueryParams { pub limit: Option, pub offset: Option, pub sort_order: Option, + pub name: Option, } #[actix_web::post("")] @@ -56,7 +57,13 @@ async fn get_all(pool: Data, options: Query, user: User) -> let mut query = sqlx::QueryBuilder::new(format!("SELECT * FROM {}", Main::TABLE_NAME)); query.push(" WHERE 1=1"); - // TODO: ADD more filters + if let Some(name) = &options.name { + if !name.is_empty() { + query.push(" AND name ILIKE "); + query.push_bind(format!("%{}%", name)); + query.push(" ESCAPE '\\'"); + } + } query.push(" ORDER BY name "); if sort_asc { diff --git a/backend/src/routes/flavor.rs b/backend/src/routes/flavor.rs index 7a5a489..447c11c 100644 --- a/backend/src/routes/flavor.rs +++ b/backend/src/routes/flavor.rs @@ -22,6 +22,7 @@ struct QueryParams { pub limit: Option, pub offset: Option, pub sort_order: Option, + pub name: Option, } #[actix_web::post("")] @@ -57,7 +58,13 @@ async fn get_all(pool: Data, options: Query, user: User) -> let mut query = sqlx::QueryBuilder::new(format!("SELECT * FROM {}", Main::TABLE_NAME)); query.push(" WHERE 1=1"); - // TODO: ADD more filters + if let Some(name) = &options.name { + if !name.is_empty() { + query.push(" AND name ILIKE "); + query.push_bind(format!("%{}%", name)); + query.push(" ESCAPE '\\'"); + } + } query.push(" ORDER BY name "); if sort_asc { diff --git a/backend/src/routes/ingredient.rs b/backend/src/routes/ingredient.rs index e24d26e..b716445 100644 --- a/backend/src/routes/ingredient.rs +++ b/backend/src/routes/ingredient.rs @@ -8,6 +8,7 @@ use actix_web::{ HttpResponse, Responder, Scope, web::{Data, Json, Path, Query}, }; +use chrono::{DateTime, Utc}; use serde::Deserialize; use sqlx::PgPool; use uuid::Uuid; @@ -21,6 +22,10 @@ struct QueryParams { pub limit: Option, pub offset: Option, pub sort_order: Option, + pub lot: Option, + pub finished_before: Option>, + pub finished_after: Option>, + pub ingredient_type: Option, } #[actix_web::post("")] @@ -56,7 +61,25 @@ async fn get_all(pool: Data, options: Query, user: User) -> let mut query = sqlx::QueryBuilder::new(format!("SELECT * FROM {}", Main::TABLE_NAME)); query.push(" WHERE 1=1"); - // TODO: ADD more filters + if let Some(lot) = &options.lot { + if !lot.is_empty() { + query.push(" AND name ILIKE "); + query.push_bind(format!("%{}%", lot)); + query.push(" ESCAPE '\\'"); + } + } + if let Some(ingredient_type) = &options.ingredient_type { + query.push(" AND ingredient_type = "); + query.push_bind(ingredient_type); + } + if let Some(finished_before) = &options.finished_before { + query.push(" AND date_finished < "); + query.push_bind(finished_before); + } + if let Some(finished_after) = &options.finished_after { + query.push(" AND date_finished > "); + query.push_bind(finished_after); + } query.push(" ORDER BY date_recieved "); if sort_asc { diff --git a/backend/src/routes/order.rs b/backend/src/routes/order.rs index 2d6d634..d011e0e 100644 --- a/backend/src/routes/order.rs +++ b/backend/src/routes/order.rs @@ -56,9 +56,7 @@ async fn get_all(pool: Data, options: Query, user: User) -> let mut query = sqlx::QueryBuilder::new(format!("SELECT * FROM {}", Main::TABLE_NAME)); query.push(" WHERE 1=1"); - // TODO: ADD more filters - - query.push(" ORDER BY invoice_number "); + query.push(" ORDER BY created_at "); if sort_asc { query.push("ASC"); } else { @@ -327,4 +325,7 @@ pub fn service() -> Scope { .service(get_all) .service(patch) .service(delete) + .service(get_items) + .service(add_item) + .service(remove_item) }