Integrate debt management features into Falukant daemon: Added falukant_debtors module for handling debtor logic, including daily processing and SQL queries for managing debtors' status and actions. Updated FalukantFamilyWorker to incorporate debtor checks and error handling, enhancing financial interactions and family dynamics.

This commit is contained in:
Torsten Schulz (local)
2026-03-23 11:56:12 +01:00
parent 9d7f61a329
commit e811ec6264
6 changed files with 753 additions and 10 deletions

View File

@@ -1144,9 +1144,278 @@ pub const QUERY_CLEANUP_CREDITS: &str = r#"
WHERE remaining_amount <= 0.01;
"#;
pub const QUERY_ADD_CHARACTER_TO_DEBTORS_PRISM: &str = r#"
INSERT INTO falukant_data.debtors_prism (character_id)
VALUES ($1);
// --- Falukant: Schuldturm & Pfändung (docs/FALUKANT_DEBTORS_DAEMON.md) ---
pub const QUERY_DEBTORS_PRISM_SCHEMA_READY: &str = r#"
SELECT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'falukant_data'
AND table_name = 'debtors_prism'
AND column_name = 'days_overdue'
) AS ready;
"#;
pub const QUERY_DEBTORS_CREDIT_USERS_FOR_DAILY: &str = r#"
SELECT
c.falukant_user_id AS user_id,
MIN(ch.id) AS character_id,
COALESCE(fu.money, 0)::float8 AS money,
COALESCE(SUM(
c.amount::float8 / 10.0
+ c.amount::float8 * c.interest_rate::float8 / 100.0
), 0)::float8 AS total_pay_rate,
COALESCE(SUM(c.remaining_amount), 0)::float8 AS total_credit_remaining
FROM falukant_data.credit c
JOIN falukant_data.falukant_user fu ON fu.id = c.falukant_user_id
JOIN falukant_data.character ch ON ch.user_id = c.falukant_user_id AND ch.health > 0
WHERE c.remaining_amount > 0.01
GROUP BY c.falukant_user_id, fu.money;
"#;
pub const QUERY_DEBTORS_GET_PRISM_BY_CHARACTER: &str = r#"
SELECT
dp.id,
dp.character_id,
COALESCE(dp.status, '') AS status,
COALESCE(dp.days_overdue, 0)::int AS days_overdue,
COALESCE(dp.remaining_debt, 0)::float8 AS remaining_debt,
dp.entered_at::text AS entered_at,
dp.released_at::text AS released_at
FROM falukant_data.debtors_prism dp
WHERE dp.character_id = $1::int
LIMIT 1;
"#;
pub const QUERY_DEBTORS_INSERT_DELINQUENT: &str = r#"
INSERT INTO falukant_data.debtors_prism (
character_id,
status,
days_overdue,
remaining_debt,
next_forced_action,
reason,
creditworthiness_penalty,
public_known,
assets_seized_json
)
SELECT
$1::int,
'delinquent',
1,
$2::float8,
'reminder',
'delinquent',
0,
false,
'{}'::jsonb
WHERE NOT EXISTS (
SELECT 1 FROM falukant_data.debtors_prism d2 WHERE d2.character_id = $1::int
)
RETURNING id;
"#;
pub const QUERY_DEBTORS_INCREMENT_DELINQUENT: &str = r#"
UPDATE falukant_data.debtors_prism
SET days_overdue = COALESCE(days_overdue, 0) + 1,
remaining_debt = $2::float8,
next_forced_action = CASE
WHEN COALESCE(days_overdue, 0) + 1 >= 3 THEN 'asset_seizure'
WHEN COALESCE(days_overdue, 0) + 1 = 2 THEN 'final_warning'
ELSE 'reminder'
END,
updated_at = NOW()
WHERE character_id = $1::int
AND status = 'delinquent'
RETURNING id, COALESCE(days_overdue, 0) AS new_days;
"#;
/// Nach abgeschlossenem Fall (`released`) neuer Verzug: Zeile wieder auf Delinquent setzen.
pub const QUERY_DEBTORS_REACTIVATE_DELINQUENT_FROM_RELEASED: &str = r#"
UPDATE falukant_data.debtors_prism
SET status = 'delinquent',
days_overdue = 1,
remaining_debt = $2::float8,
next_forced_action = 'reminder',
reason = 'delinquent',
updated_at = NOW()
WHERE character_id = $1::int
AND status = 'released'
RETURNING id;
"#;
pub const QUERY_DEBTORS_RESET_DELINQUENCY_SOLVENT: &str = r#"
UPDATE falukant_data.debtors_prism
SET days_overdue = 0,
next_forced_action = 'reminder',
updated_at = NOW()
WHERE character_id = $1::int
AND status = 'delinquent';
"#;
pub const QUERY_DEBTORS_RESET_ON_PAYMENT_SUCCESS: &str = r#"
UPDATE falukant_data.debtors_prism
SET days_overdue = 0,
next_forced_action = 'reminder',
updated_at = NOW()
WHERE character_id = $1::int
AND status = 'delinquent';
"#;
pub const QUERY_DEBTORS_ENTER_PRISON: &str = r#"
UPDATE falukant_data.debtors_prism
SET status = 'imprisoned',
entered_at = COALESCE(entered_at, NOW()),
released_at = NULL,
debt_at_entry = $2::float8,
remaining_debt = $2::float8,
reason = 'credit_default',
creditworthiness_penalty = COALESCE(creditworthiness_penalty, 0) + 45,
next_forced_action = 'asset_seizure',
public_known = true,
updated_at = NOW()
WHERE character_id = $1::int
AND status = 'delinquent'
AND COALESCE(days_overdue, 0) >= 3
RETURNING id;
"#;
pub const QUERY_DEBTORS_RELEASE_IF_PAID: &str = r#"
UPDATE falukant_data.debtors_prism dp
SET status = 'released',
released_at = NOW(),
next_forced_action = NULL,
days_overdue = 0,
remaining_debt = 0,
updated_at = NOW()
FROM falukant_data.character ch
WHERE ch.id = dp.character_id
AND ch.user_id = $1::int
AND dp.status = 'imprisoned'
AND COALESCE((
SELECT SUM(c.remaining_amount)
FROM falukant_data.credit c
WHERE c.falukant_user_id = $1::int
), 0) <= 0.01
RETURNING dp.character_id;
"#;
pub const QUERY_DEBTORS_SUBTRACT_REPUTATION: &str = r#"
UPDATE falukant_data.character
SET reputation = GREATEST(0::numeric, COALESCE(reputation, 50::numeric) - $2::numeric),
updated_at = NOW()
WHERE id = $1::int AND user_id IS NOT NULL;
"#;
pub const QUERY_DEBTORS_MARRIAGE_SATISFACTION_SUB: &str = r#"
UPDATE falukant_data.relationship r
SET marriage_satisfaction = GREATEST(0, COALESCE(r.marriage_satisfaction, 55) - $2::int),
updated_at = NOW()
FROM falukant_type.relationship rt
WHERE rt.id = r.relationship_type_id
AND rt.tr IN ('married', 'engaged', 'wooing')
AND (r.character1_id = $1::int OR r.character2_id = $1::int);
"#;
pub const QUERY_DEBTORS_HOUSEHOLD_TENSION_ADD: &str = r#"
UPDATE falukant_data.user_house
SET household_tension_score = LEAST(100, COALESCE(household_tension_score, 0) + $2::int),
updated_at = NOW()
WHERE user_id = $1::int;
"#;
pub const QUERY_DEBTORS_LOVER_AFFECTION_SUB: &str = r#"
UPDATE falukant_data.relationship_state rs
SET affection = GREATEST(0, COALESCE(rs.affection, 50) - $2::int),
updated_at = NOW()
FROM falukant_data.relationship r
JOIN falukant_type.relationship rt ON rt.id = r.relationship_type_id AND rt.tr = 'lover'
WHERE rs.relationship_id = r.id
AND rs.active = true
AND (r.character1_id = $1::int OR r.character2_id = $1::int);
"#;
pub const QUERY_DEBTORS_IMPRISONED_REP_MALUS: &str = r#"
UPDATE falukant_data.character c
SET reputation = GREATEST(0::numeric, COALESCE(c.reputation, 50::numeric) - $2::numeric),
updated_at = NOW()
WHERE c.id = $1::int AND c.user_id IS NOT NULL;
"#;
pub const QUERY_DEBTORS_IMPRISONED_PENALTY_PLUS1: &str = r#"
UPDATE falukant_data.debtors_prism
SET creditworthiness_penalty = COALESCE(creditworthiness_penalty, 0) + 1,
updated_at = NOW()
WHERE character_id = $1::int AND status = 'imprisoned';
"#;
pub const QUERY_DEBTORS_IMPRISONED_MARRIAGE_SUB1: &str = r#"
UPDATE falukant_data.relationship r
SET marriage_satisfaction = GREATEST(0, COALESCE(r.marriage_satisfaction, 55) - 1),
updated_at = NOW()
FROM falukant_type.relationship rt
WHERE rt.id = r.relationship_type_id
AND rt.tr IN ('married', 'engaged', 'wooing')
AND (r.character1_id = $1::int OR r.character2_id = $1::int);
"#;
pub const QUERY_DEBTORS_IMPRISONED_TENSION_PLUS2: &str = r#"
UPDATE falukant_data.user_house uh
SET household_tension_score = LEAST(100, COALESCE(uh.household_tension_score, 0) + 2),
updated_at = NOW()
FROM falukant_data.character ch
WHERE ch.id = $1::int AND uh.user_id = ch.user_id;
"#;
pub const QUERY_DEBTORS_IMPRISONED_LOVER_AFF_SUB2: &str = r#"
UPDATE falukant_data.relationship_state rs
SET affection = GREATEST(0, COALESCE(rs.affection, 50) - 2),
updated_at = NOW()
FROM falukant_data.relationship r
JOIN falukant_type.relationship rt ON rt.id = r.relationship_type_id AND rt.tr = 'lover'
WHERE rs.relationship_id = r.id AND rs.active = true
AND (r.character1_id = $1::int OR r.character2_id = $1::int);
"#;
pub const QUERY_DEBTORS_VEHICLE_FOR_SEIZURE: &str = r#"
SELECT v.id AS vehicle_id,
COALESCE(v.condition, 100)::int AS veh_condition,
COALESCE(vt.cost, 0)::float8 AS type_cost
FROM falukant_data.vehicle v
JOIN falukant_type.vehicle vt ON vt.id = v.vehicle_type_id
WHERE v.falukant_user_id = $1::int
AND v.id NOT IN (
SELECT DISTINCT t.vehicle_id FROM falukant_data.transport t
WHERE t.vehicle_id IS NOT NULL
)
ORDER BY COALESCE(vt.cost, 0) ASC, v.id ASC
LIMIT 1;
"#;
pub const QUERY_DEBTORS_DELETE_VEHICLE: &str = r#"
DELETE FROM falukant_data.vehicle WHERE id = $1::int RETURNING id;
"#;
pub const QUERY_DEBTORS_UPDATE_PRISM_REMAINING: &str = r#"
UPDATE falukant_data.debtors_prism dp
SET remaining_debt = GREATEST(0, COALESCE(dp.remaining_debt, 0) - $2::float8),
assets_seized_json = COALESCE(assets_seized_json, '{}'::jsonb)
|| jsonb_build_object(
'last_vehicle',
jsonb_build_object('vehicle_id', $3::int, 'proceeds', $2::float8)
),
updated_at = NOW()
WHERE dp.character_id = $1::int AND dp.status = 'imprisoned'
RETURNING dp.remaining_debt;
"#;
pub const QUERY_DEBTORS_UPDATE_PRISM_REMAINING_MONEY: &str = r#"
UPDATE falukant_data.debtors_prism dp
SET remaining_debt = GREATEST(0, COALESCE(dp.remaining_debt, 0) - $2::float8),
assets_seized_json = COALESCE(assets_seized_json, '{}'::jsonb)
|| jsonb_build_object('last_cash_seizure', $2::float8),
updated_at = NOW()
WHERE dp.character_id = $1::int AND dp.status = 'imprisoned'
RETURNING dp.remaining_debt;
"#;
pub const QUERY_RANDOM_HEIR: &str = r#"