179 lines
5.1 KiB
Rust
179 lines
5.1 KiB
Rust
|
|
use chrono::{DateTime, Utc};
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
use sqlx::{FromRow, PgPool};
|
||
|
|
use uuid::Uuid;
|
||
|
|
|
||
|
|
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||
|
|
pub struct Requirement {
|
||
|
|
pub id: Uuid,
|
||
|
|
pub customer_id: Uuid,
|
||
|
|
pub profession_key: String,
|
||
|
|
pub title: String,
|
||
|
|
pub description: String,
|
||
|
|
pub location: String,
|
||
|
|
pub budget: Option<i32>,
|
||
|
|
pub preferred_date: Option<chrono::NaiveDate>,
|
||
|
|
pub extra_data_json: Option<serde_json::Value>,
|
||
|
|
pub status: String, // DRAFT, PENDING_APPROVAL, OPEN, CLOSED, EXPIRED, REJECTED
|
||
|
|
pub rejection_reason: Option<String>,
|
||
|
|
pub request_count: i32,
|
||
|
|
pub accepted_count: i32,
|
||
|
|
pub expires_at: Option<DateTime<Utc>>,
|
||
|
|
pub approved_at: Option<DateTime<Utc>>,
|
||
|
|
pub approved_by: Option<Uuid>,
|
||
|
|
pub created_at: DateTime<Utc>,
|
||
|
|
pub updated_at: DateTime<Utc>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Serialize, Deserialize)]
|
||
|
|
pub struct CreateRequirementPayload {
|
||
|
|
pub customer_id: Uuid,
|
||
|
|
pub profession_key: String,
|
||
|
|
pub title: String,
|
||
|
|
pub description: String,
|
||
|
|
pub location: String,
|
||
|
|
pub budget: Option<i32>,
|
||
|
|
pub preferred_date: Option<chrono::NaiveDate>,
|
||
|
|
pub extra_data_json: Option<serde_json::Value>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Serialize, Deserialize)]
|
||
|
|
pub struct UpdateRequirementPayload {
|
||
|
|
pub title: Option<String>,
|
||
|
|
pub description: Option<String>,
|
||
|
|
pub location: Option<String>,
|
||
|
|
pub budget: Option<i32>,
|
||
|
|
pub preferred_date: Option<chrono::NaiveDate>,
|
||
|
|
pub extra_data_json: Option<serde_json::Value>,
|
||
|
|
}
|
||
|
|
|
||
|
|
pub struct RequirementRepository;
|
||
|
|
|
||
|
|
impl RequirementRepository {
|
||
|
|
pub async fn create(
|
||
|
|
pool: &PgPool,
|
||
|
|
payload: CreateRequirementPayload,
|
||
|
|
) -> Result<Requirement, sqlx::Error> {
|
||
|
|
let req = sqlx::query_as!(
|
||
|
|
Requirement,
|
||
|
|
r#"
|
||
|
|
INSERT INTO requirements (
|
||
|
|
customer_id, profession_key, title, description, location,
|
||
|
|
budget, preferred_date, extra_data_json
|
||
|
|
)
|
||
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||
|
|
RETURNING *
|
||
|
|
"#,
|
||
|
|
payload.customer_id,
|
||
|
|
payload.profession_key,
|
||
|
|
payload.title,
|
||
|
|
payload.description,
|
||
|
|
payload.location,
|
||
|
|
payload.budget,
|
||
|
|
payload.preferred_date,
|
||
|
|
payload.extra_data_json
|
||
|
|
)
|
||
|
|
.fetch_one(pool)
|
||
|
|
.await?;
|
||
|
|
|
||
|
|
Ok(req)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Requirement>, sqlx::Error> {
|
||
|
|
sqlx::query_as!(Requirement, "SELECT * FROM requirements WHERE id = $1", id)
|
||
|
|
.fetch_optional(pool)
|
||
|
|
.await
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn list_by_customer_id(
|
||
|
|
pool: &PgPool,
|
||
|
|
customer_id: Uuid,
|
||
|
|
page: i64,
|
||
|
|
limit: i64,
|
||
|
|
) -> Result<Vec<Requirement>, sqlx::Error> {
|
||
|
|
let offset = (page - 1) * limit;
|
||
|
|
let reqs = sqlx::query_as!(
|
||
|
|
Requirement,
|
||
|
|
r#"
|
||
|
|
SELECT * FROM requirements
|
||
|
|
WHERE customer_id = $1
|
||
|
|
ORDER BY created_at DESC
|
||
|
|
LIMIT $2 OFFSET $3
|
||
|
|
"#,
|
||
|
|
customer_id,
|
||
|
|
limit,
|
||
|
|
offset
|
||
|
|
)
|
||
|
|
.fetch_all(pool)
|
||
|
|
.await?;
|
||
|
|
|
||
|
|
Ok(reqs)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn update(
|
||
|
|
pool: &PgPool,
|
||
|
|
id: Uuid,
|
||
|
|
payload: UpdateRequirementPayload,
|
||
|
|
) -> Result<Requirement, sqlx::Error> {
|
||
|
|
let req = sqlx::query_as!(
|
||
|
|
Requirement,
|
||
|
|
r#"
|
||
|
|
UPDATE requirements SET
|
||
|
|
title = COALESCE($1, title),
|
||
|
|
description = COALESCE($2, description),
|
||
|
|
location = COALESCE($3, location),
|
||
|
|
budget = COALESCE($4, budget),
|
||
|
|
preferred_date = COALESCE($5, preferred_date),
|
||
|
|
extra_data_json = COALESCE($6, extra_data_json),
|
||
|
|
updated_at = NOW()
|
||
|
|
WHERE id = $7
|
||
|
|
RETURNING *
|
||
|
|
"#,
|
||
|
|
payload.title,
|
||
|
|
payload.description,
|
||
|
|
payload.location,
|
||
|
|
payload.budget,
|
||
|
|
payload.preferred_date,
|
||
|
|
payload.extra_data_json,
|
||
|
|
id
|
||
|
|
)
|
||
|
|
.fetch_one(pool)
|
||
|
|
.await?;
|
||
|
|
|
||
|
|
Ok(req)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn update_status(
|
||
|
|
pool: &PgPool,
|
||
|
|
id: Uuid,
|
||
|
|
status: &str,
|
||
|
|
) -> Result<Requirement, sqlx::Error> {
|
||
|
|
let req = sqlx::query_as!(
|
||
|
|
Requirement,
|
||
|
|
"UPDATE requirements SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *",
|
||
|
|
status,
|
||
|
|
id
|
||
|
|
)
|
||
|
|
.fetch_one(pool)
|
||
|
|
.await?;
|
||
|
|
Ok(req)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn increment_request_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
|
||
|
|
sqlx::query!("UPDATE requirements SET request_count = request_count + 1 WHERE id = $1", id)
|
||
|
|
.execute(pool)
|
||
|
|
.await?;
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn increment_accepted_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
|
||
|
|
sqlx::query!(
|
||
|
|
"UPDATE requirements SET accepted_count = accepted_count + 1 WHERE id = $1",
|
||
|
|
id
|
||
|
|
)
|
||
|
|
.execute(pool)
|
||
|
|
.await?;
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|