Verbessere Preisberechnung im DirectorWorker: Implementiere kumulative Steuerberechnung basierend auf regionalen Büros und deren Befreiungen, um die Genauigkeit der Einnahmen und Auszahlungen zu erhöhen.
This commit is contained in:
@@ -1001,40 +1001,102 @@ impl DirectorWorker {
|
|||||||
|
|
||||||
let sell_price = piece_sell_price * item.quantity as f64;
|
let sell_price = piece_sell_price * item.quantity as f64;
|
||||||
|
|
||||||
// Steuerberechnung und Auszahlung: Berechne in Cent und runde wie JS Math.round
|
// Steuerberechnung: 1) Region ermitteln, 2) user offices, 3) cumulative tax (mit Befreiungen)
|
||||||
let revenue_cents = (sell_price * 100.0).round() as i64;
|
let mut cumulative_tax_percent = DEFAULT_TAX_PERCENT;
|
||||||
// Produktionskosten nicht direkt verfügbar hier, wir approximieren profit als revenue
|
|
||||||
// (wenn präzisere Kosten nötig sind, kann man production_cost übergeben)
|
|
||||||
let cost_cents = 0i64;
|
|
||||||
|
|
||||||
let tax_percent = DEFAULT_TAX_PERCENT;
|
conn.prepare("get_branch_region", "SELECT region_id FROM falukant_data.branch WHERE id = $1;")?;
|
||||||
|
let branch_rows = conn.execute("get_branch_region", &[&item.branch_id])?;
|
||||||
|
let branch_region_id: Option<i32> = branch_rows.get(0).and_then(|r| r.get("region_id")).and_then(|v| v.parse().ok());
|
||||||
|
|
||||||
|
if let Some(region_id) = branch_region_id {
|
||||||
|
// user offices
|
||||||
|
conn.prepare(
|
||||||
|
"get_user_offices",
|
||||||
|
"SELECT po.id AS office_id, pot.name AS office_name, po.region_id, rt.label_tr AS region_type FROM falukant_data.political_office po JOIN falukant_type.political_office_type pot ON pot.id = po.office_type_id JOIN falukant_data.region r ON r.id = po.region_id JOIN falukant_type.region_type rt ON rt.id = r.region_type_id WHERE po.holder_id = $1 AND (po.end_date IS NULL OR po.end_date > NOW());",
|
||||||
|
)?;
|
||||||
|
let offices = conn.execute("get_user_offices", &[&item.user_id])?;
|
||||||
|
|
||||||
|
let mut exempt_types: Vec<String> = Vec::new();
|
||||||
|
let mut has_chancellor = false;
|
||||||
|
for row in &offices {
|
||||||
|
if let Some(name) = row.get("office_name") {
|
||||||
|
match name.as_str() {
|
||||||
|
"chancellor" => { has_chancellor = true; break; }
|
||||||
|
"council" => { exempt_types.push("city".to_string()); }
|
||||||
|
"taxman" => { exempt_types.extend(["city","county"].into_iter().map(String::from)); }
|
||||||
|
"treasurerer" => { exempt_types.extend(["city","county","shire"].into_iter().map(String::from)); }
|
||||||
|
"super-state-administrator" => { exempt_types.extend(["city","county","shire","markgrave","duchy"].into_iter().map(String::from)); }
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_chancellor {
|
||||||
|
cumulative_tax_percent = 0.0;
|
||||||
|
} else {
|
||||||
|
if exempt_types.is_empty() {
|
||||||
|
conn.prepare(
|
||||||
|
"cumulative_tax_no_exempt",
|
||||||
|
"WITH RECURSIVE ancestors AS (SELECT id, parent_id, COALESCE(tax_percent,0.0) AS tax_percent FROM falukant_data.region WHERE id = $1 UNION ALL SELECT r.id, r.parent_id, COALESCE(r.tax_percent,0.0) FROM falukant_data.region r JOIN ancestors a ON r.id = a.parent_id) SELECT COALESCE(SUM(tax_percent),0.0) AS total_percent FROM ancestors;",
|
||||||
|
)?;
|
||||||
|
let res = conn.execute("cumulative_tax_no_exempt", &[®ion_id])?;
|
||||||
|
if let Some(row) = res.get(0) {
|
||||||
|
if let Some(tp) = row.get("total_percent") {
|
||||||
|
cumulative_tax_percent = tp.parse::<f64>().unwrap_or(DEFAULT_TAX_PERCENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conn.prepare(
|
||||||
|
"cumulative_tax_with_exempt",
|
||||||
|
"WITH RECURSIVE ancestors AS (SELECT r.id, r.parent_id, CASE WHEN rt.label_tr = ANY($2::text[]) THEN 0.0 ELSE COALESCE(r.tax_percent,0.0) END AS tax_percent FROM falukant_data.region r JOIN falukant_type.region_type rt ON rt.id = r.region_type_id WHERE r.id = $1 UNION ALL SELECT r.id, r.parent_id, CASE WHEN rt.label_tr = ANY($2::text[]) THEN 0.0 ELSE COALESCE(r.tax_percent,0.0) END FROM falukant_data.region r JOIN falukant_type.region_type rt ON rt.id = r.region_type_id JOIN ancestors a ON r.id = a.parent_id) SELECT COALESCE(SUM(tax_percent),0.0) AS total_percent FROM ancestors;",
|
||||||
|
)?;
|
||||||
|
let exempt_array: Vec<&str> = exempt_types.iter().map(|s| s.as_str()).collect();
|
||||||
|
let res = conn.execute("cumulative_tax_with_exempt", &[®ion_id, &exempt_array])?;
|
||||||
|
if let Some(row) = res.get(0) {
|
||||||
|
if let Some(tp) = row.get("total_percent") {
|
||||||
|
cumulative_tax_percent = tp.parse::<f64>().unwrap_or(DEFAULT_TAX_PERCENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produktkosten (original_sell_cost fallback sell_cost)
|
||||||
|
conn.prepare("get_product_cost", "SELECT original_sell_cost, sell_cost FROM falukant_type.product WHERE id = $1")?;
|
||||||
|
let cost_rows = conn.execute("get_product_cost", &[&item.product_id])?;
|
||||||
|
let mut one_piece_cost = item.sell_cost;
|
||||||
|
if let Some(row) = cost_rows.get(0) {
|
||||||
|
if let Some(osc) = row.get("original_sell_cost") {
|
||||||
|
if let Ok(v) = osc.parse::<f64>() {
|
||||||
|
one_piece_cost = v;
|
||||||
|
}
|
||||||
|
} else if let Some(sc) = row.get("sell_cost") {
|
||||||
|
if let Ok(v) = sc.parse::<f64>() {
|
||||||
|
one_piece_cost = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cents-based arithmetic
|
||||||
|
let revenue_cents = (sell_price * 100.0).round() as i64;
|
||||||
|
let cost_cents = (one_piece_cost * item.quantity as f64 * 100.0).round() as i64;
|
||||||
let profit_cents = (revenue_cents - cost_cents).max(0);
|
let profit_cents = (revenue_cents - cost_cents).max(0);
|
||||||
let tax_cents = ((profit_cents as f64) * (tax_percent / 100.0)).round() as i64;
|
let tax_cents = ((profit_cents as f64) * cumulative_tax_percent / 100.0).round() as i64;
|
||||||
let payout_cents = revenue_cents - tax_cents;
|
let payout_cents = revenue_cents - tax_cents;
|
||||||
|
|
||||||
// Credit tax to treasury
|
eprintln!("[DirectorWorker] sell: revenue={:.2}, cost={:.2}, profit_cents={}, tax%={:.2}, tax_cents={}, payout_cents={}", sell_price, one_piece_cost * item.quantity as f64, profit_cents, cumulative_tax_percent, tax_cents, payout_cents);
|
||||||
|
|
||||||
if tax_cents > 0 {
|
if tax_cents > 0 {
|
||||||
let tax_amount = (tax_cents as f64) / 100.0;
|
let tax_amount = (tax_cents as f64) / 100.0;
|
||||||
if let Err(err) = self.base.change_falukant_user_money(
|
if let Err(err) = self.base.change_falukant_user_money(DEFAULT_TREASURY_USER_ID, tax_amount, &format!("tax from sale product {}", item.product_id)) {
|
||||||
DEFAULT_TREASURY_USER_ID,
|
|
||||||
tax_amount,
|
|
||||||
&format!("tax from sale product {}", item.product_id),
|
|
||||||
) {
|
|
||||||
eprintln!("[DirectorWorker] Fehler bei change_falukant_user_money (tax): {err}");
|
eprintln!("[DirectorWorker] Fehler bei change_falukant_user_money (tax): {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Payout to seller
|
|
||||||
let payout_amount = (payout_cents as f64) / 100.0;
|
let payout_amount = (payout_cents as f64) / 100.0;
|
||||||
if payout_cents != 0 {
|
if payout_cents != 0 {
|
||||||
if let Err(err) = self.base.change_falukant_user_money(
|
if let Err(err) = self.base.change_falukant_user_money(item.user_id, payout_amount, "sell products") {
|
||||||
item.user_id,
|
eprintln!("[DirectorWorker] Fehler bei change_falukant_user_money (sell products): {err}");
|
||||||
payout_amount,
|
|
||||||
"sell products",
|
|
||||||
) {
|
|
||||||
eprintln!(
|
|
||||||
"[DirectorWorker] Fehler bei change_falukant_user_money (sell products): {err}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user