Implement director resignation processing in DirectorWorker: Added logic to check for director resignations based on satisfaction levels, including new SQL queries for retrieving candidates and deleting directors. Enhanced notification system to alert users of high resignation risks, improving overall management of director statuses.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m32s
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m32s
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use crate::db::{DbConnection, DbError, Row};
|
||||
use rand::Rng;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use crate::message_broker::MessageBroker;
|
||||
use std::sync::atomic::Ordering;
|
||||
@@ -26,6 +27,8 @@ use crate::worker::sql::{
|
||||
QUERY_SET_SALARY_PAYED,
|
||||
QUERY_UPDATE_SATISFACTION,
|
||||
QUERY_GET_DIRECTOR_USER,
|
||||
QUERY_GET_DIRECTORS_FOR_RESIGNATION_CHECK,
|
||||
QUERY_DELETE_DIRECTOR_BY_ID,
|
||||
QUERY_COUNT_VEHICLES_IN_BRANCH_REGION,
|
||||
QUERY_COUNT_VEHICLES_IN_REGION,
|
||||
QUERY_CHECK_ROUTE,
|
||||
@@ -36,6 +39,7 @@ use crate::worker::sql::{
|
||||
QUERY_GET_USER_OFFICES,
|
||||
QUERY_CUMULATIVE_TAX_NO_EXEMPT,
|
||||
QUERY_CUMULATIVE_TAX_WITH_EXEMPT,
|
||||
QUERY_INSERT_NOTIFICATION,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -47,6 +51,14 @@ struct Director {
|
||||
may_start_transport: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct DirectorResignationCandidate {
|
||||
id: i32,
|
||||
employer_user_id: i32,
|
||||
director_character_id: i32,
|
||||
satisfaction: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ProductionPlan {
|
||||
falukant_user_id: i32,
|
||||
@@ -91,6 +103,7 @@ struct TransportVehicle {
|
||||
pub struct DirectorWorker {
|
||||
base: BaseWorker,
|
||||
last_run: Option<Instant>,
|
||||
last_resignation_check: Option<Instant>,
|
||||
}
|
||||
|
||||
// Maximale Anzahl paralleler Produktionen pro Branch
|
||||
@@ -114,6 +127,7 @@ impl DirectorWorker {
|
||||
Self {
|
||||
base: BaseWorker::new("DirectorWorker", pool, broker),
|
||||
last_run: None,
|
||||
last_resignation_check: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +155,84 @@ impl DirectorWorker {
|
||||
self.perform_task()?;
|
||||
self.pay_salary()?;
|
||||
self.calculate_satisfaction()?;
|
||||
self.process_director_resignations()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_director_resignations(&mut self) -> Result<(), DbError> {
|
||||
let now = Instant::now();
|
||||
let should_run = match self.last_resignation_check {
|
||||
None => true,
|
||||
Some(last) => now.saturating_duration_since(last) >= Duration::from_secs(24 * 60 * 60),
|
||||
};
|
||||
if !should_run {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut conn = self
|
||||
.base
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
conn.prepare(
|
||||
"get_directors_for_resignation_check",
|
||||
QUERY_GET_DIRECTORS_FOR_RESIGNATION_CHECK,
|
||||
)?;
|
||||
conn.prepare("delete_director_by_id", QUERY_DELETE_DIRECTOR_BY_ID)?;
|
||||
conn.prepare("insert_notification", QUERY_INSERT_NOTIFICATION)?;
|
||||
|
||||
let rows = conn.execute("get_directors_for_resignation_check", &[])?;
|
||||
let candidates: Vec<DirectorResignationCandidate> = rows
|
||||
.into_iter()
|
||||
.filter_map(Self::map_row_to_resignation_candidate)
|
||||
.collect();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
for candidate in candidates {
|
||||
let sat = candidate.satisfaction.clamp(0, 100) as f64;
|
||||
let resignation_probability = 1.0 - (sat / 100.0);
|
||||
if resignation_probability > 0.5 {
|
||||
let risk_percent = (resignation_probability * 100.0 * 100.0).round() / 100.0;
|
||||
let payload = format!(
|
||||
r#"{{"tr":"director.resignation_risk_high","event":"director_resignation_risk_high","director_id":{},"director_character_id":{},"risk_percent":{},"satisfaction":{},"threshold_percent":50}}"#,
|
||||
candidate.id,
|
||||
candidate.director_character_id,
|
||||
risk_percent,
|
||||
candidate.satisfaction.clamp(0, 100)
|
||||
);
|
||||
let _ = conn.execute("insert_notification", &[&candidate.employer_user_id, &payload]);
|
||||
}
|
||||
let roll: f64 = rng.gen_range(0.0..1.0);
|
||||
if roll >= resignation_probability {
|
||||
continue;
|
||||
}
|
||||
|
||||
let deleted = conn.execute("delete_director_by_id", &[&candidate.id])?;
|
||||
if deleted.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"[DirectorWorker] Director {} kündigt (character_id={}, user_id={}, satisfaction={}, prob={:.4}, roll={:.4})",
|
||||
candidate.id,
|
||||
candidate.director_character_id,
|
||||
candidate.employer_user_id,
|
||||
candidate.satisfaction,
|
||||
resignation_probability,
|
||||
roll
|
||||
);
|
||||
|
||||
self.base.broker.publish(format!(
|
||||
r#"{{"event":"directorchanged","user_id":{}}}"#,
|
||||
candidate.employer_user_id
|
||||
));
|
||||
self.base.broker.publish(format!(
|
||||
r#"{{"event":"falukantUpdateStatus","user_id":{}}}"#,
|
||||
candidate.employer_user_id
|
||||
));
|
||||
}
|
||||
|
||||
self.last_resignation_check = Some(now);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -198,6 +290,15 @@ impl DirectorWorker {
|
||||
})
|
||||
}
|
||||
|
||||
fn map_row_to_resignation_candidate(row: Row) -> Option<DirectorResignationCandidate> {
|
||||
Some(DirectorResignationCandidate {
|
||||
id: row.get("id")?.parse().ok()?,
|
||||
employer_user_id: row.get("employer_user_id")?.parse().ok()?,
|
||||
director_character_id: row.get("director_character_id")?.parse().ok()?,
|
||||
satisfaction: row.get("satisfaction")?.parse().ok()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn start_productions(&mut self, director: &Director) -> Result<(), DbError> {
|
||||
self.base
|
||||
.set_current_step("DirectorWorker: start_productions");
|
||||
|
||||
@@ -638,6 +638,21 @@ pub const QUERY_GET_DIRECTOR_USER: &str = r#"
|
||||
SELECT fu.id AS falukant_user_id FROM falukant_data.director d JOIN falukant_data.falukant_user fu ON fu.id = d.employer_user_id WHERE d.id = $1 LIMIT 1;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_DIRECTORS_FOR_RESIGNATION_CHECK: &str = r#"
|
||||
SELECT d.id,
|
||||
d.employer_user_id,
|
||||
d.director_character_id,
|
||||
COALESCE(d.satisfaction, 0)::int AS satisfaction
|
||||
FROM falukant_data.director d
|
||||
WHERE d.employer_user_id IS NOT NULL;
|
||||
"#;
|
||||
|
||||
pub const QUERY_DELETE_DIRECTOR_BY_ID: &str = r#"
|
||||
DELETE FROM falukant_data.director
|
||||
WHERE id = $1::int
|
||||
RETURNING employer_user_id, director_character_id;
|
||||
"#;
|
||||
|
||||
pub const QUERY_COUNT_VEHICLES_IN_BRANCH_REGION: &str = r#"
|
||||
SELECT COUNT(v.id) AS cnt FROM falukant_data.vehicle v WHERE v.falukant_user_id = $1 AND v.region_id = $2;
|
||||
"#;
|
||||
|
||||
Reference in New Issue
Block a user