Add debug functionality for best production selection: Introduced a new SQL query QUERY_GET_BEST_PRODUCTION_DEBUG to retrieve the top 5 production candidates with detailed metrics. Enhanced the DirectorWorker to log debug information during production selection, improving traceability of decision-making processes.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m35s
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m35s
This commit is contained in:
@@ -10,6 +10,7 @@ use super::base::{BaseWorker, Worker, WorkerState, DEFAULT_TAX_PERCENT, DEFAULT_
|
||||
use crate::worker::sql::{
|
||||
QUERY_GET_DIRECTORS,
|
||||
QUERY_GET_BEST_PRODUCTION,
|
||||
QUERY_GET_BEST_PRODUCTION_DEBUG,
|
||||
QUERY_INSERT_PRODUCTION,
|
||||
QUERY_GET_BRANCH_CAPACITY,
|
||||
QUERY_GET_INVENTORY,
|
||||
@@ -208,12 +209,62 @@ impl DirectorWorker {
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
|
||||
// Initial: Bestes Produkt für diesen Branch ermitteln
|
||||
conn.prepare("get_to_produce_debug", QUERY_GET_BEST_PRODUCTION_DEBUG)?;
|
||||
let debug_rows = conn.execute("get_to_produce_debug", &[&director.id, &director.branch_id])?;
|
||||
for (idx, row) in debug_rows.iter().enumerate() {
|
||||
let rank = idx + 1;
|
||||
let product_id = row.get("product_id").map(|s| s.as_str()).unwrap_or("?");
|
||||
let label = row.get("label_tr").map(|s| s.as_str()).unwrap_or("?");
|
||||
let category = row.get("product_category").map(|s| s.as_str()).unwrap_or("?");
|
||||
let production_time = row.get("production_time").map(|s| s.as_str()).unwrap_or("?");
|
||||
let sell_cost = row.get("sell_cost").map(|s| s.as_str()).unwrap_or("?");
|
||||
let market_percent = row.get("market_percent").map(|s| s.as_str()).unwrap_or("?");
|
||||
let knowledge_character = row.get("knowledge_character").map(|s| s.as_str()).unwrap_or("?");
|
||||
let knowledge_director = row.get("knowledge_director").map(|s| s.as_str()).unwrap_or("?");
|
||||
let effective_percent = row.get("effective_percent").map(|s| s.as_str()).unwrap_or("?");
|
||||
let one_piece_cost = row.get("one_piece_cost").map(|s| s.as_str()).unwrap_or("?");
|
||||
let revenue_piece = row.get("revenue_piece").map(|s| s.as_str()).unwrap_or("?");
|
||||
let worth = row.get("worth").map(|s| s.as_str()).unwrap_or("?");
|
||||
eprintln!(
|
||||
"[DirectorWorker][best_production_debug] director_id={} branch_id={} rank={} product_id={} label={} cat={} prod_time={} sell_cost={} market%={} knowledge(char={},dir={}) effective%={} one_piece_cost={} revenue_piece={} worth={}",
|
||||
director.id,
|
||||
director.branch_id,
|
||||
rank,
|
||||
product_id,
|
||||
label,
|
||||
category,
|
||||
production_time,
|
||||
sell_cost,
|
||||
market_percent,
|
||||
knowledge_character,
|
||||
knowledge_director,
|
||||
effective_percent,
|
||||
one_piece_cost,
|
||||
revenue_piece,
|
||||
worth
|
||||
);
|
||||
}
|
||||
|
||||
conn.prepare("get_to_produce", QUERY_GET_BEST_PRODUCTION)?;
|
||||
let rows = conn.execute("get_to_produce", &[&director.id, &director.branch_id])?;
|
||||
if rows.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(row) = rows.first() {
|
||||
let product_id = row.get("product_id").map(|s| s.as_str()).unwrap_or("?");
|
||||
let label = row.get("label_tr").map(|s| s.as_str()).unwrap_or("?");
|
||||
let worth = row.get("worth").map(|s| s.as_str()).unwrap_or("?");
|
||||
eprintln!(
|
||||
"[DirectorWorker][best_production_selected] director_id={} branch_id={} product_id={} label={} worth={}",
|
||||
director.id,
|
||||
director.branch_id,
|
||||
product_id,
|
||||
label,
|
||||
worth
|
||||
);
|
||||
}
|
||||
|
||||
let mut base_plan = match rows.first().and_then(Self::map_row_to_production_plan) {
|
||||
Some(p) => p,
|
||||
None => return Ok(()),
|
||||
|
||||
@@ -1,25 +1,6 @@
|
||||
use crate::db::{ConnectionPool, DbConnection, DbError};
|
||||
use crate::message_broker::MessageBroker;
|
||||
use crate::db::{DbConnection, DbError};
|
||||
use crate::worker::sql::QUERY_INSERT_NOTIFICATION;
|
||||
|
||||
/// Schreibt eine Notification in `falukant_log.notification`.
|
||||
///
|
||||
/// - `tr` ist ein (i.d.R. JSON-)String, den das Frontend parst.
|
||||
/// - `character_id` ist optional (NULL).
|
||||
pub fn insert_notification(
|
||||
pool: &ConnectionPool,
|
||||
user_id: i32,
|
||||
tr: &str,
|
||||
character_id: Option<i32>,
|
||||
) -> Result<(), DbError> {
|
||||
let mut conn = pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
|
||||
insert_notification_conn(&mut conn, user_id, tr, character_id)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Variante für bestehende DB-Verbindungen (spart Connect/Prepare in Loops).
|
||||
pub fn insert_notification_conn(
|
||||
conn: &mut DbConnection,
|
||||
@@ -35,11 +16,3 @@ pub fn insert_notification_conn(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Informiert das Frontend, dass sich der Status geändert hat (z.B. Branches neu laden).
|
||||
pub fn publish_update_status(broker: &MessageBroker, user_id: i32) {
|
||||
broker.publish(format!(
|
||||
r#"{{"event":"falukantUpdateStatus","user_id":{}}}"#,
|
||||
user_id
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,152 @@ JOIN falukant_data.knowledge fdk_director ON fdk_director.product_id = ftp.id AN
|
||||
WHERE fdd.id = $1 AND fdb.id = $2 ORDER BY worth DESC LIMIT 1;
|
||||
"#;
|
||||
|
||||
/// Debug-Variante zur Nachvollziehbarkeit der Direktoren-Entscheidung.
|
||||
/// Liefert die Top-5 Kandidaten inkl. Teilmetriken, die in `worth` einfließen.
|
||||
pub const QUERY_GET_BEST_PRODUCTION_DEBUG: &str = r#"
|
||||
SELECT
|
||||
ftp.id AS product_id,
|
||||
ftp.label_tr,
|
||||
COALESCE(ftp.category, 1)::int AS product_category,
|
||||
COALESCE(ftp.production_time, 0)::int AS production_time,
|
||||
ROUND(ftp.sell_cost::numeric, 2) AS sell_cost,
|
||||
ROUND(
|
||||
(
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM falukant_data.vehicle v
|
||||
WHERE v.falukant_user_id = fdu.id
|
||||
)
|
||||
THEN bw.max_worth_pct
|
||||
ELSE COALESCE(fdtpw_local.worth_percent::float8, 0.0)
|
||||
END
|
||||
)::numeric,
|
||||
2
|
||||
) AS market_percent,
|
||||
COALESCE(fdk_character.knowledge, 0)::int AS knowledge_character,
|
||||
COALESCE(fdk_director.knowledge, 0)::int AS knowledge_director,
|
||||
ROUND(
|
||||
(
|
||||
(
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM falukant_data.vehicle v
|
||||
WHERE v.falukant_user_id = fdu.id
|
||||
)
|
||||
THEN bw.max_worth_pct
|
||||
ELSE COALESCE(fdtpw_local.worth_percent::float8, 0.0)
|
||||
END
|
||||
)
|
||||
+ (2.0 * COALESCE(fdk_character.knowledge, 0)::float8 + COALESCE(fdk_director.knowledge, 0)::float8) / 3.0
|
||||
)::numeric,
|
||||
2
|
||||
) AS effective_percent,
|
||||
ROUND(
|
||||
(
|
||||
(
|
||||
6.0 + GREATEST(COALESCE(ftp.category, 1)::float8, 1.0)
|
||||
) * (
|
||||
1.0 - LEAST(
|
||||
GREATEST(
|
||||
COALESCE(fdu.certificate, 1)::float8
|
||||
- GREATEST(COALESCE(ftp.category, 1)::float8, 1.0),
|
||||
0.0
|
||||
) * 0.035,
|
||||
0.14
|
||||
)
|
||||
)
|
||||
)::numeric,
|
||||
4
|
||||
) AS one_piece_cost,
|
||||
ROUND(
|
||||
(
|
||||
ftp.sell_cost
|
||||
* (
|
||||
(
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM falukant_data.vehicle v
|
||||
WHERE v.falukant_user_id = fdu.id
|
||||
)
|
||||
THEN bw.max_worth_pct
|
||||
ELSE COALESCE(fdtpw_local.worth_percent::float8, 0.0)
|
||||
END
|
||||
)
|
||||
+ (2.0 * COALESCE(fdk_character.knowledge, 0)::float8 + COALESCE(fdk_director.knowledge, 0)::float8) / 3.0
|
||||
) / 100.0
|
||||
)::numeric,
|
||||
4
|
||||
) AS revenue_piece,
|
||||
ROUND(
|
||||
(
|
||||
(
|
||||
ftp.sell_cost
|
||||
* (
|
||||
(
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM falukant_data.vehicle v
|
||||
WHERE v.falukant_user_id = fdu.id
|
||||
)
|
||||
THEN bw.max_worth_pct
|
||||
ELSE COALESCE(fdtpw_local.worth_percent::float8, 0.0)
|
||||
END
|
||||
)
|
||||
+ (2.0 * COALESCE(fdk_character.knowledge, 0)::float8 + COALESCE(fdk_director.knowledge, 0)::float8) / 3.0
|
||||
) / 100.0
|
||||
- (
|
||||
(
|
||||
6.0 + GREATEST(COALESCE(ftp.category, 1)::float8, 1.0)
|
||||
) * (
|
||||
1.0 - LEAST(
|
||||
GREATEST(
|
||||
COALESCE(fdu.certificate, 1)::float8
|
||||
- GREATEST(COALESCE(ftp.category, 1)::float8, 1.0),
|
||||
0.0
|
||||
) * 0.035,
|
||||
0.14
|
||||
)
|
||||
)
|
||||
)
|
||||
) / (300.0 * NULLIF(ftp.production_time::float8, 0.0))
|
||||
)::numeric,
|
||||
8
|
||||
) AS worth
|
||||
FROM falukant_data.director fdd
|
||||
JOIN falukant_data.character fdc ON fdc.id = fdd.director_character_id
|
||||
JOIN falukant_data.falukant_user fdu ON fdd.employer_user_id = fdu.id
|
||||
JOIN falukant_data.character user_character
|
||||
ON user_character.id = (
|
||||
SELECT c2.id
|
||||
FROM falukant_data.character c2
|
||||
WHERE c2.user_id = fdu.id
|
||||
AND c2.health > 0
|
||||
ORDER BY c2.id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
JOIN falukant_data.branch fdb ON fdb.falukant_user_id = fdu.id AND fdb.region_id = fdc.region_id
|
||||
JOIN (
|
||||
SELECT tpw.product_id,
|
||||
MAX(tpw.worth_percent)::float8 AS max_worth_pct
|
||||
FROM falukant_data.town_product_worth tpw
|
||||
WHERE tpw.region_id IN (
|
||||
SELECT DISTINCT br.region_id
|
||||
FROM falukant_data.branch br
|
||||
WHERE br.falukant_user_id = (SELECT d0.employer_user_id FROM falukant_data.director d0 WHERE d0.id = $1::int)
|
||||
)
|
||||
GROUP BY tpw.product_id
|
||||
) bw ON TRUE
|
||||
JOIN falukant_type.product ftp ON ftp.id = bw.product_id AND ftp.category <= fdu.certificate
|
||||
LEFT JOIN falukant_data.town_product_worth fdtpw_local
|
||||
ON fdtpw_local.region_id = fdb.region_id
|
||||
AND fdtpw_local.product_id = ftp.id
|
||||
JOIN falukant_data.knowledge fdk_character ON fdk_character.product_id = ftp.id AND fdk_character.character_id = user_character.id
|
||||
JOIN falukant_data.knowledge fdk_director ON fdk_director.product_id = ftp.id AND fdk_director.character_id = fdd.director_character_id
|
||||
WHERE fdd.id = $1 AND fdb.id = $2
|
||||
ORDER BY worth DESC
|
||||
LIMIT 5;
|
||||
"#;
|
||||
|
||||
pub const QUERY_INSERT_PRODUCTION: &str = r#"
|
||||
INSERT INTO falukant_data.production (branch_id, product_id, quantity, weather_type_id) VALUES ($1, $2, $3, (SELECT weather_type_id FROM falukant_data.weather WHERE region_id = $4));
|
||||
"#;
|
||||
@@ -2694,10 +2840,7 @@ pub const QUERY_SET_MARRIAGES_BY_PARTY: &str = r#"
|
||||
SELECT id
|
||||
FROM falukant_type.relationship AS rt
|
||||
WHERE rt.tr = 'married'
|
||||
),
|
||||
marriage_satisfaction = 55,
|
||||
marriage_drift_high = 0,
|
||||
marriage_drift_low = 0
|
||||
)
|
||||
WHERE rel.id IN (
|
||||
SELECT rel2.id
|
||||
FROM falukant_data.party AS p
|
||||
|
||||
Reference in New Issue
Block a user