Refactor production cost calculations and SQL query: Updated the QUERY_GET_BEST_PRODUCTION to align profit calculations with the new logic for selling prices based on knowledge levels. Enhanced documentation to clarify the ranking criteria and the relationship between production costs and pricing strategies. Adjusted related functions in director.rs to ensure consistency across the application.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 2m54s
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 2m54s
This commit is contained in:
@@ -41,13 +41,17 @@ effektiv_stückkosten = raw × (1 − discount)
|
||||
| `PRODUCTION_HEADROOM_DISCOUNT_PER_STEP` | `0.035` | Rabatt pro Headroom-Stufe |
|
||||
| `PRODUCTION_HEADROOM_DISCOUNT_CAP` | `0.14` | maximaler Gesamtrabatt |
|
||||
|
||||
## Worth in SQL (`QUERY_GET_BEST_PRODUCTION`)
|
||||
## Ranking in SQL (`QUERY_GET_BEST_PRODUCTION`)
|
||||
|
||||
Sortierung nach **regionalem Erlös pro Zeiteinheit**:
|
||||
Sortierung nach **Gewinn pro Minute**, mit **demselben Verkaufs-Modell** wie `DirectorWorker::compute_piece_price_for_percent` / `compute_piece_sell_price` in `director.rs`:
|
||||
|
||||
`(sell_cost * worth_percent/100) / production_time`
|
||||
1. **Regionaler Basispreis:** `sell_cost × (worth_percent / 100)` — mit Fahrzeug `MAX(worth_percent)` über alle Filialregionen des Users, sonst nur Region der Direktor-Filiale.
|
||||
2. **Wissensband:** effektiver Verkaufspreis = Basis × **`0.6 + 0.4 × (k/100)`** mit k = Wissen 0…100 (linear zwischen 60 % und 100 % der Basis). Entspricht `min_price + (max_price − min_price) × k/100` mit `min = 0.6 × Basis`, `max = Basis`.
|
||||
3. **k:** `(2 × knowledge Spielercharakter + knowledge Direktor) / 3` aus `falukant_data.knowledge` (Produktzeilen für Charakter bzw. Direktor).
|
||||
4. **Stückkosten:** wie `piece_production_cost` (siehe oben).
|
||||
5. **Formel:** `(Verkaufspreis/Stück − Stückkosten) / production_time`. **Steuer** im Ranking nicht abgezogen.
|
||||
|
||||
Damit entspricht die Auswahl in etwa **„Erlös pro Minute“** (Listenpreis × Markt in der Region ÷ Dauer einer Produktionscharge). **Wissen** fließt hier **nicht** in die Reihenfolge ein (Wissen wirkt bei euch auf Qualität/Preis beim Verkauf, nicht auf die Produktwahl). Die **Stückkosten** kommen nur aus der Rust-Formel beim Abbuchen.
|
||||
**UI / Node:** Sollte dieselbe Preislogik wie der Daemon nutzen. Weicht `calcRegionalSellPriceSync` ab (z. B. 70 % statt 60 % unterhalb der Basis), Frontend an **diese** Rust-Formel anpassen — nicht umgekehrt den Daemon „blind“ an eine abweichende UI koppeln.
|
||||
|
||||
## Parallelproduktionen
|
||||
|
||||
|
||||
@@ -657,7 +657,7 @@ impl DirectorWorker {
|
||||
})
|
||||
}
|
||||
|
||||
// Helper: compute piece sell price from item fields
|
||||
// Helper: compute piece sell price from item fields (QUERY_GET_BEST_PRODUCTION nutzt dieselbe 0.6/0.4-Logik mit knowledge)
|
||||
fn compute_piece_sell_price(item: &InventoryItem) -> f64 {
|
||||
let base_price = item.sell_cost * (item.worth_percent / 100.0);
|
||||
let min_price = base_price * 0.6;
|
||||
@@ -1028,7 +1028,7 @@ impl DirectorWorker {
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
// Helper: compute piece price for an arbitrary worth_percent
|
||||
/// Wie `QUERY_GET_BEST_PRODUCTION`: Basis `sell_cost×worth/100`, Verkauf linear zwischen 60 % und 100 % der Basis.
|
||||
fn compute_piece_price_for_percent(item: &InventoryItem, percent: f64) -> f64 {
|
||||
let base_price = item.sell_cost * (percent / 100.0);
|
||||
let min_price = base_price * 0.6;
|
||||
|
||||
@@ -73,9 +73,14 @@ JOIN falukant_data.branch b ON b.region_id = c.region_id AND b.falukant_user_id
|
||||
WHERE current_time BETWEEN '08:00:00' AND '17:00:00';
|
||||
"#;
|
||||
|
||||
/// Bester Produktstart: **Gewinn pro Minute** (wie UI „Gewinn/Minute“) ≈ `(Erlös/Stück − Stückkosten) / Produktionszeit`.
|
||||
/// Stückkosten = gleiche Formel wie `Director::piece_production_cost` (Basis 6 + Kategorie, Headroom-Rabatt).
|
||||
/// Marktpreis: mit Fahrzeug `MAX(worth_percent)` über Filialregionen, sonst nur Direktor-Region. **Ohne** Steuer im Ranking.
|
||||
/// Bester Produktstart: **Gewinn pro Minute** ≈ `(Verkaufspreis/Stück − Stückkosten) / Produktionszeit` — an
|
||||
/// `DirectorWorker::compute_piece_price_for_percent` angeglichen: regionaler Basispreis
|
||||
/// `sell_cost × worth/100`, dann linear **60 %–100 %** dieser Basis je nach Wissen (0–100), gleiche Idee wie
|
||||
/// `min_price + (max−min)×k/100` in `director.rs`. Wissensblend `(2×Charakter + Direktor)/3`. UI soll dieselbe
|
||||
/// Logik nutzen; weicht das Node-Frontend ab (z. B. 70 % statt 60 %), dort angleichen.
|
||||
///
|
||||
/// Stückkosten wie `Director::piece_production_cost`. Mit Fahrzeug: `MAX(worth_percent)` über Filialregionen;
|
||||
/// ohne Fahrzeug: nur Direktor-Region. **Ohne** Steuer im Ranking.
|
||||
pub const QUERY_GET_BEST_PRODUCTION: &str = r#"
|
||||
SELECT fdu.id falukant_user_id, CAST(fdu.money AS text) AS money, fdu.certificate, ftp.id product_id, ftp.label_tr,
|
||||
COALESCE(ftp.category, 1)::int AS product_category, fdb.region_id,
|
||||
@@ -83,15 +88,28 @@ COALESCE(ftp.category, 1)::int AS product_category, fdb.region_id,
|
||||
COALESCE((SELECT SUM(COALESCE(fdi.quantity, 0)) FROM falukant_data.stock fds JOIN falukant_data.inventory fdi ON fdi.stock_id = fds.id WHERE fds.branch_id = fdb.id), 0) AS used_in_stock,
|
||||
(
|
||||
(
|
||||
ftp.sell_cost * (
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM falukant_data.vehicle v
|
||||
WHERE v.falukant_user_id = fdu.id
|
||||
(
|
||||
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 / 100.0
|
||||
)
|
||||
) * (
|
||||
0.6 + 0.4 * LEAST(
|
||||
100.0::float8,
|
||||
GREATEST(
|
||||
0.0::float8,
|
||||
(
|
||||
2.0 * COALESCE(fdk_character.knowledge, 0)::float8
|
||||
+ COALESCE(fdk_director.knowledge, 0)::float8
|
||||
) / 3.0
|
||||
)
|
||||
THEN bw.max_worth_pct
|
||||
ELSE COALESCE(fdtpw_local.worth_percent::float8, 0.0)
|
||||
END / 100.0
|
||||
) / 100.0
|
||||
)
|
||||
- (
|
||||
(6.0 + (GREATEST(COALESCE(ftp.category, 1), 1))::float8)
|
||||
|
||||
Reference in New Issue
Block a user