From 801d37202e60f20f8b8f913b34e9937f582507a5 Mon Sep 17 00:00:00 2001 From: Wes Holland Date: Mon, 16 Jun 2025 15:36:16 -0500 Subject: [PATCH] Hook up import from file --- src/app/routes.rs | 2 +- src/app/upload/vetcove.rs | 2 +- src/db/vetcove/item_history.rs | 19 ++++++-- src/db/vetcove/mod.rs | 2 +- src/ingest/vetcove.rs | 86 +++++++++++++++++++++++++++------- 5 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/app/routes.rs b/src/app/routes.rs index aec2ad4..aa127e0 100644 --- a/src/app/routes.rs +++ b/src/app/routes.rs @@ -47,7 +47,7 @@ pub fn routes() -> Router { ) .route("/upload", get(upload::index::upload_index_handler)) .route("/upload/catalog", post(upload::catalog::catalog_import)) - .route("/upload/vetcove/order", post(upload::vetcove::order_details_import)) + .route("/upload/vetcove/history", post(upload::vetcove::item_history_import)) .route("/overview", get(overview::overview_handler)) .route("/reports", get(reports::reports_handler)) .route("/history", get(history::history_log_handler)) diff --git a/src/app/upload/vetcove.rs b/src/app/upload/vetcove.rs index 2a31cdc..da7cb3d 100644 --- a/src/app/upload/vetcove.rs +++ b/src/app/upload/vetcove.rs @@ -7,7 +7,7 @@ use crate::error::AppError; use crate::session::SessionUser; use crate::ingest::vetcove::ingest_item_history_bytes; -pub async fn order_details_import( +pub async fn item_history_import( State(db): State, user: SessionUser, mut multipart: Multipart, diff --git a/src/db/vetcove/item_history.rs b/src/db/vetcove/item_history.rs index 0a11166..05eb9e6 100644 --- a/src/db/vetcove/item_history.rs +++ b/src/db/vetcove/item_history.rs @@ -1,7 +1,7 @@ use serde::Serialize; use anyhow::Result; -use chrono::{DateTime, Utc}; +use chrono::{DateTime, NaiveDate, Utc}; use sqlx::SqlitePool; #[derive(Clone, Debug, Serialize)] @@ -36,7 +36,7 @@ pub struct DbVetcoveItemHistoryEntry { pub async fn add_vetcove_item_history_entry(db: &SqlitePool, vetcove_entry_id: i64, vetcove_item_id: i64, - order_date: DateTime, + order_date: NaiveDate, item_name: String, order_id: String, units: f64, @@ -55,7 +55,16 @@ pub async fn add_vetcove_item_history_entry(db: &SqlitePool, unit_measurement: Option, item_status: Option, supplier_sku: Option) - -> Result { + -> Result> { + + let existing: i64 = sqlx::query_scalar(r#" + SELECT COUNT(1) FROM VetcoveItemHistory WHERE vetcove_entry_id = ? + "#).bind(vetcove_entry_id).fetch_one(db).await?; + + if existing > 0 { + return Ok(None) + } + let res = sqlx::query( r#" INSERT INTO VetcoveItemHistory ( @@ -104,8 +113,8 @@ pub async fn add_vetcove_item_history_entry(db: &SqlitePool, .bind(item_status) .bind(supplier_sku) .execute(db).await?; - + let new_id = res.last_insert_rowid(); - Ok(new_id) + Ok(Some(new_id)) } diff --git a/src/db/vetcove/mod.rs b/src/db/vetcove/mod.rs index 54d4bb8..b46226f 100644 --- a/src/db/vetcove/mod.rs +++ b/src/db/vetcove/mod.rs @@ -1 +1 @@ -mod item_history; \ No newline at end of file +pub mod item_history; \ No newline at end of file diff --git a/src/ingest/vetcove.rs b/src/ingest/vetcove.rs index e5ae7e4..a49ade1 100644 --- a/src/ingest/vetcove.rs +++ b/src/ingest/vetcove.rs @@ -4,18 +4,52 @@ use tracing::info; use axum::body::Bytes; use crate::db::adjustment::add_adjustment_new_stock; use crate::db::inventory_item::add_inventory_item; +use crate::db::vetcove::item_history::add_vetcove_item_history_entry; #[derive(Debug, serde::Deserialize)] struct ItemHistoryRecord { - name: String, - #[serde(alias = "qty")] + #[serde(alias = "Vetcove ID")] + vetcove_entry_id: i64, + #[serde(alias = "Date")] + order_date: chrono::NaiveDate, + #[serde(alias = "Hospital")] + hospital: String, + #[serde(alias = "Name")] + item_name: String, + #[serde(alias = "Order #")] + order_id: String, + #[serde(alias = "PO Number")] + po_number: String, + #[serde(alias = "Supplier")] + supplier: String, + #[serde(alias = "Manufacturer")] + manufacturer: String, + #[serde(alias = "Manufacturer Number")] + manufacturer_number: String, + #[serde(alias = "Primary Category")] + primary_category: String, + #[serde(alias = "Secondary Category")] + secondary_category: String, + #[serde(alias = "Vetcove Item ID")] + vetcove_item_id: i64, + #[serde(alias = "Cost per Dose")] + cost_per_dose: String, + #[serde(alias = "Units")] + units: f64, + #[serde(alias = "Unit Price")] + unit_price: String, + #[serde(alias = "Unit Measurement")] + unit_measurement: String, + #[serde(alias = "List Price")] + list_price: String, + #[serde(alias = "Quantity")] quantity: f64, - unit: String, - fractional: bool, - #[serde(alias = "reorder")] - reorder_point: f64, - #[serde(alias = "price")] - unit_price: i64, + #[serde(alias = "Total Price")] + total_price: String, + #[serde(alias = "Item Status")] + item_status: String, + #[serde(alias = "Supplier's SKU")] + supplier_sku: String, } pub async fn ingest_item_history_bytes(bytes: Bytes, db: SqlitePool, user_id: i64) -> anyhow::Result<()> { @@ -31,17 +65,35 @@ pub async fn ingest_item_history(mut reader: csv::Reader, d for result in reader.deserialize() { let record: ItemHistoryRecord = result?; - /* - let new_entry_id = add_inventory_item(&db, - &record.name, - record.reorder_point, - record.fractional, - &record.unit, - &None, - &None, + let query_res = add_vetcove_item_history_entry( + &db, + record.vetcove_entry_id, + record.vetcove_item_id, + record.order_date, + record.item_name, + record.order_id, + record.units, + record.quantity, + record.total_price, + Some(record.unit_price), + Some(record.list_price), + Some(record.cost_per_dose), + Some(record.hospital), + Some(record.po_number), + Some(record.supplier), + Some(record.manufacturer), + Some(record.manufacturer_number), + Some(record.primary_category), + Some(record.secondary_category), + Some(record.unit_measurement), + Some(record.item_status), + Some(record.supplier_sku), ).await?; - */ + match query_res { + Some(new_db_id) => info!("Added new history item: {} => {}", record.vetcove_entry_id, new_db_id), + None => info!("History item exists, skipping {}", record.vetcove_entry_id), + } } Ok(()) }