Skip to content

Commit 25607ff

Browse files
committed
update hospital inventory
1 parent 360d71d commit 25607ff

4 files changed

Lines changed: 105 additions & 0 deletions

File tree

src/docs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use crate::handlers::{auth, hospitals, patients, appointments, specialists, admi
3939
hospitals::get_donor_history,
4040
hospitals::get_dashboard_stats,
4141
hospitals::get_recent_activity,
42+
hospitals::update_blood_inventory,
4243
specialists::create_specialist,
4344
specialists::get_specialist,
4445
specialists::get_specialists,

src/handlers/hospitals.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ pub struct UpdateHospitalSettingsRequest {
112112
pub push_notifications: Option<bool>,
113113
}
114114

115+
#[derive(Debug, Deserialize, ToSchema)]
116+
pub struct UpdateBloodInventoryRequest {
117+
pub units_available: Option<i32>,
118+
pub bank_capacity: Option<i32>,
119+
}
120+
115121
/// Create hospital
116122
#[utoipa::path(
117123
post,
@@ -622,6 +628,40 @@ pub async fn upload_accreditation_doc(
622628
url,
623629
))
624630
}
631+
/// Update blood inventory for a specific blood type
632+
#[utoipa::path(
633+
patch,
634+
path = "/api/hospitals/inventory/{hospital_id}/{blood_type}",
635+
request_body = UpdateBloodInventoryRequest,
636+
responses(
637+
(status = 200, body = ApiResponse<crate::models::HospitalBloodInventory>),
638+
(status = 401),
639+
(status = 404),
640+
(status = 500)
641+
),
642+
tag = "hospitals",
643+
security(("bearer_auth" = []))
644+
)]
645+
pub async fn update_blood_inventory(
646+
State(state): State<AppState>,
647+
Path((hospital_id, blood_type)): Path<(Uuid, BloodTypeEnum)>,
648+
Extension(user): Extension<User>,
649+
Json(payload): Json<UpdateBloodInventoryRequest>,
650+
) -> Result<ApiResponse<crate::models::HospitalBloodInventory>, AppError> {
651+
let mut conn = state.pool.get()?;
652+
let inventory = hospitals::service::update_blood_inventory(
653+
&mut conn,
654+
hospital_id,
655+
&user,
656+
blood_type,
657+
payload,
658+
)?;
659+
660+
Ok(ApiResponse::success_with_message(
661+
"Blood inventory updated successfully",
662+
inventory,
663+
))
664+
}
625665

626666
/// Get all hospitals
627667
#[utoipa::path(

src/hospitals/service.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,66 @@ pub fn get_hospital_inventory(
330330
.load::<crate::models::HospitalBloodInventory>(conn)
331331
.map_err(AppError::from)
332332
}
333+
pub fn update_blood_inventory(
334+
conn: &mut PgConnection,
335+
h_id: Uuid,
336+
user: &User,
337+
b_type: crate::utils::enums::BloodTypeEnum,
338+
payload: crate::handlers::hospitals::UpdateBloodInventoryRequest,
339+
) -> Result<crate::models::HospitalBloodInventory, AppError> {
340+
use crate::schema::hospital_blood_inventories::dsl::*;
341+
use crate::schema::hospitals::dsl as h;
342+
343+
// Check if hospital exists and belongs to user (or user is admin)
344+
let hospital_exists = h::hospitals
345+
.filter(h::id.eq(h_id))
346+
.filter(h::user_id.eq(user.id))
347+
.select(h::id)
348+
.first::<Uuid>(conn)
349+
.optional()?;
350+
351+
if hospital_exists.is_none() {
352+
return Err(AppError::NotFound(
353+
"Hospital not found or unauthorized".into(),
354+
));
355+
}
356+
357+
let mut update_query = diesel::update(
358+
hospital_blood_inventories
359+
.filter(hospital_id.eq(h_id))
360+
.filter(blood_type.eq(b_type.clone())),
361+
)
362+
.into_boxed();
363+
364+
// Perform the update
365+
let result = diesel::update(
366+
hospital_blood_inventories
367+
.filter(hospital_id.eq(h_id))
368+
.filter(blood_type.eq(b_type.clone())),
369+
)
370+
.set((
371+
payload.units_available.map(|v| units_available.eq(v)),
372+
payload.bank_capacity.map(|v| bank_capacity.eq(v)),
373+
updated_at.eq(chrono::Utc::now()),
374+
))
375+
.get_result::<crate::models::HospitalBloodInventory>(conn)
376+
.optional()?;
377+
378+
match result {
379+
Some(inventory) => Ok(inventory),
380+
None => {
381+
// If it doesn't exist, we could choose to create it or return 404.
382+
// Given it's an "update" endpoint, 404 seems more appropriate unless we want UPSERT.
383+
// However, the existing UpdateHospitalRequest does UPSERT. Let's do UPSERT for consistency if needed,
384+
// but the user asked to "update", and usually inventory is initialized.
385+
// Let's stick to update for now, but provide a helpful error.
386+
Err(AppError::NotFound(format!(
387+
"Inventory for blood type {:?} not found in this hospital",
388+
b_type
389+
)))
390+
}
391+
}
392+
}
333393

334394
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
335395
pub struct DonorQuery {

src/routes/hospitals.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,8 @@ pub fn protected_router() -> Router<AppState> {
4949
"/dashboard/recent-activity",
5050
get(hospitals::get_recent_activity),
5151
)
52+
.route(
53+
"/inventory/{hospital_id}/{blood_type}",
54+
patch(hospitals::update_blood_inventory),
55+
)
5256
}

0 commit comments

Comments
 (0)