Files
manager_employees_rust/src/database/queries/schedule.rs
T
2026-09-18 12:45:11 -04:00

135 lines
3.7 KiB
Rust

use chrono::NaiveDateTime;
use sqlx::PgPool;
use crate::database::{entities::Schedule, types::DayOfWeek};
pub async fn add_schedule(
pool: &PgPool,
user_id: i32,
enter_time: NaiveDateTime,
day_of_week: DayOfWeek,
out_time: NaiveDateTime,
) -> Result<Schedule, sqlx::Error> {
// Keep compatible with legacy DBs that have an extra `shift` column.
// Try insert with `shift` first, fall back to 4-column insert if the column was dropped/never created.
let with_shift = sqlx::query_as::<_, Schedule>(
r#"
INSERT INTO schedules (user_id, enter_time, day_of_week, shift, out_time)
VALUES ($1, $2, $3, 'morning', $4)
RETURNING id, user_id, enter_time, day_of_week, out_time, date_created, date_updated
"#,
)
.bind(user_id)
.bind(enter_time)
.bind(day_of_week)
.bind(out_time)
.fetch_one(pool)
.await;
match with_shift {
Ok(schedule) => Ok(schedule),
Err(_) => {
sqlx::query_as::<_, Schedule>(
r#"
INSERT INTO schedules (user_id, enter_time, day_of_week, out_time)
VALUES ($1, $2, $3, $4)
RETURNING id, user_id, enter_time, day_of_week, out_time, date_created, date_updated
"#,
)
.bind(user_id)
.bind(enter_time)
.bind(day_of_week)
.bind(out_time)
.fetch_one(pool)
.await
}
}
}
pub async fn list_schedules(pool: &PgPool) -> Result<Vec<Schedule>, sqlx::Error> {
sqlx::query_as::<_, Schedule>(
r#"
SELECT id, user_id, enter_time, day_of_week, out_time, date_created, date_updated
FROM schedules
ORDER BY day_of_week, user_id
"#,
)
.fetch_all(pool)
.await
}
pub async fn list_schedules_for_company(
pool: &PgPool,
company_id: i32,
) -> Result<Vec<Schedule>, sqlx::Error> {
sqlx::query_as::<_, Schedule>(
r#"
SELECT schedules.id, schedules.user_id, schedules.enter_time, schedules.day_of_week,
schedules.out_time, schedules.date_created, schedules.date_updated
FROM schedules
INNER JOIN company_users ON company_users.user_id = schedules.user_id
WHERE company_users.company_id = $1
ORDER BY schedules.day_of_week, schedules.user_id
"#,
)
.bind(company_id)
.fetch_all(pool)
.await
}
pub async fn delete_schedules_for_company(
pool: &PgPool,
company_id: i32,
) -> Result<(), sqlx::Error> {
sqlx::query(
r#"
DELETE FROM schedules
USING company_users
WHERE company_users.user_id = schedules.user_id
AND company_users.company_id = $1
"#,
)
.bind(company_id)
.execute(pool)
.await?;
Ok(())
}
pub async fn clock_in(
pool: &PgPool,
user_id: i32,
now: NaiveDateTime,
day_of_week: DayOfWeek,
) -> Result<Schedule, sqlx::Error> {
// out_time is required in reference API, initialize with enter_time and let clock-out update it
add_schedule(pool, user_id, now, day_of_week, now).await
}
pub async fn clock_out(
pool: &PgPool,
user_id: i32,
day_of_week: DayOfWeek,
out_time: NaiveDateTime,
) -> Result<Schedule, sqlx::Error> {
sqlx::query_as::<_, Schedule>(
r#"
UPDATE schedules
SET out_time = $3, date_updated = NOW()
WHERE id = (
SELECT id
FROM schedules
WHERE user_id = $1 AND day_of_week = $2
ORDER BY enter_time DESC
LIMIT 1
)
RETURNING id, user_id, enter_time, day_of_week, out_time, date_created, date_updated
"#,
)
.bind(user_id)
.bind(day_of_week)
.bind(out_time)
.fetch_one(pool)
.await
}