headless_lms_models/
course_module_suotar_realisations.rs1use utoipa::ToSchema;
2
3use crate::prelude::*;
4
5#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
6pub struct CourseModuleSuotarRealisation {
7 pub id: Uuid,
8 pub created_at: DateTime<Utc>,
9 pub updated_at: DateTime<Utc>,
10 pub deleted_at: Option<DateTime<Utc>>,
11 pub course_module_id: Uuid,
12 pub course_unit_realisation_id: String,
13 pub label: Option<String>,
14 pub active: bool,
15 pub last_listed_at: Option<DateTime<Utc>>,
16 pub last_listed_person_count: Option<i32>,
17 pub last_already_linked_count: Option<i32>,
18 pub last_mailed_count: Option<i32>,
19 pub last_suppressed_by_dedup_count: Option<i32>,
20 pub last_suppressed_by_rate_cap_count: Option<i32>,
21 pub last_no_address_count: Option<i32>,
22}
23
24#[derive(Debug, Clone, PartialEq, Default)]
27pub struct RealisationListingOutcome {
28 pub listed_person_count: i32,
29 pub already_linked_count: i32,
30 pub mailed_count: i32,
31 pub suppressed_by_dedup_count: i32,
32 pub suppressed_by_rate_cap_count: i32,
33 pub no_address_count: i32,
34}
35
36pub async fn upsert(
37 conn: &mut PgConnection,
38 course_module_id: Uuid,
39 course_unit_realisation_id: &str,
40 label: Option<&str>,
41 active: bool,
42) -> ModelResult<Uuid> {
43 let res = sqlx::query!(
44 r#"
45INSERT INTO course_module_suotar_realisations (
46 course_module_id,
47 course_unit_realisation_id,
48 label,
49 active
50 )
51VALUES ($1, $2, $3, $4) ON CONFLICT (
52 course_module_id,
53 course_unit_realisation_id,
54 deleted_at
55 ) DO
56UPDATE
57SET label = $3,
58 active = $4
59RETURNING id
60 "#,
61 course_module_id,
62 course_unit_realisation_id,
63 label,
64 active,
65 )
66 .fetch_one(conn)
67 .await?;
68 Ok(res.id)
69}
70
71pub async fn get_by_course_module_id(
72 conn: &mut PgConnection,
73 course_module_id: Uuid,
74) -> ModelResult<Vec<CourseModuleSuotarRealisation>> {
75 let res = sqlx::query_as!(
76 CourseModuleSuotarRealisation,
77 r#"
78SELECT *
79FROM course_module_suotar_realisations
80WHERE course_module_id = $1
81 AND deleted_at IS NULL
82ORDER BY created_at
83 "#,
84 course_module_id
85 )
86 .fetch_all(conn)
87 .await?;
88 Ok(res)
89}
90
91pub async fn get_all_active_for_enabled_modules(
93 conn: &mut PgConnection,
94) -> ModelResult<Vec<CourseModuleSuotarRealisation>> {
95 let res = sqlx::query_as!(
96 CourseModuleSuotarRealisation,
97 r#"
98SELECT cmsr.*
99FROM course_module_suotar_realisations cmsr
100 JOIN course_modules cm ON cm.id = cmsr.course_module_id
101 LEFT JOIN course_module_suotar_configurations c ON c.course_module_id = cm.id
102 AND c.deleted_at IS NULL
103WHERE cmsr.active
104 AND cmsr.deleted_at IS NULL
105 AND cm.enable_credit_registration_via_suotar
106 AND c.paused_at IS NULL
107 AND cm.deleted_at IS NULL
108ORDER BY cmsr.last_listed_at ASC NULLS FIRST
109 "#,
110 )
111 .fetch_all(conn)
112 .await?;
113 Ok(res)
114}
115
116pub async fn record_listing_outcome(
117 conn: &mut PgConnection,
118 id: Uuid,
119 outcome: &RealisationListingOutcome,
120) -> ModelResult<()> {
121 sqlx::query!(
122 r#"
123UPDATE course_module_suotar_realisations
124SET last_listed_at = now(),
125 last_listed_person_count = $2,
126 last_already_linked_count = $3,
127 last_mailed_count = $4,
128 last_suppressed_by_dedup_count = $5,
129 last_suppressed_by_rate_cap_count = $6,
130 last_no_address_count = $7
131WHERE id = $1
132 AND deleted_at IS NULL
133 "#,
134 id,
135 outcome.listed_person_count,
136 outcome.already_linked_count,
137 outcome.mailed_count,
138 outcome.suppressed_by_dedup_count,
139 outcome.suppressed_by_rate_cap_count,
140 outcome.no_address_count,
141 )
142 .execute(conn)
143 .await?;
144 Ok(())
145}
146
147pub async fn soft_delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
148 sqlx::query!(
149 r#"
150UPDATE course_module_suotar_realisations
151SET deleted_at = now()
152WHERE id = $1
153 AND deleted_at IS NULL
154 "#,
155 id
156 )
157 .execute(conn)
158 .await?;
159 Ok(())
160}