eur czk can be disabled from now on
This commit is contained in:
@@ -82,6 +82,8 @@ async fn update(
|
||||
active.rate_e4 = Set(currency::parse_rate(&form.rate)?);
|
||||
active.enabled = Set(is_checked(&form.enabled));
|
||||
active.update(&ctx.db).await?;
|
||||
// Keep the navbar/settings chrome snapshot in sync with the new rate/state.
|
||||
currency::refresh_snapshot(&ctx.db).await?;
|
||||
format::redirect("/admin/currencies")
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use loco_rs::prelude::*;
|
||||
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set};
|
||||
|
||||
use crate::models::currencies;
|
||||
use crate::shared::currency::SCALE;
|
||||
use crate::shared::currency::{self, SCALE};
|
||||
|
||||
/// `(code, symbol, default_rate_e4)` — default rate is a placeholder the admin
|
||||
/// is expected to update from the live FX rate.
|
||||
@@ -45,6 +45,8 @@ impl Initializer for CurrencySeeder {
|
||||
.await?;
|
||||
tracing::info!(currency = code, "seeded display currency");
|
||||
}
|
||||
// Prime the process-wide snapshot used by the navbar/settings chrome.
|
||||
currency::refresh_snapshot(&ctx.db).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,12 @@ impl Initializer for ViewEngineInitializer {
|
||||
crate::shared::csrf::current_token().unwrap_or_default(),
|
||||
))
|
||||
});
|
||||
// `currencies()`: the EUR base plus enabled alternative currencies
|
||||
// (from the process-wide snapshot), used by the global chrome — the
|
||||
// settings-menu switcher and the navbar exchange-rate display.
|
||||
tera.register_function("currencies", |_args: &HashMap<String, serde_json::Value>| {
|
||||
Ok(crate::shared::currency::selectable_json())
|
||||
});
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
//! [`Currency`] resolved per request converts EUR cents into the chosen currency
|
||||
//! for display only — the cart logic, orders and admin stay in EUR.
|
||||
|
||||
use std::sync::RwLock;
|
||||
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use loco_rs::prelude::*;
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder};
|
||||
|
||||
use crate::models::currencies;
|
||||
use crate::shared::money::format_price;
|
||||
@@ -99,6 +102,65 @@ pub async fn resolve(ctx: &AppContext, jar: &CookieJar) -> Currency {
|
||||
}
|
||||
}
|
||||
|
||||
/// One enabled, buyer-selectable alternative currency in the process-wide
|
||||
/// snapshot below.
|
||||
#[derive(Clone)]
|
||||
struct Selectable {
|
||||
code: String,
|
||||
symbol: String,
|
||||
rate_e4: i64,
|
||||
}
|
||||
|
||||
/// Process-wide snapshot of the enabled alternative currencies, so the global
|
||||
/// chrome (the settings-menu switcher and the navbar rate) can be rendered via a
|
||||
/// Tera function without a per-request DB hit. Loaded at boot by
|
||||
/// `initializers::currency_seeder` and refreshed by the admin on every edit (see
|
||||
/// [`refresh_snapshot`]). EUR (the base) is implicit and never listed here.
|
||||
static ENABLED: RwLock<Vec<Selectable>> = RwLock::new(Vec::new());
|
||||
|
||||
/// Reload the [`ENABLED`] snapshot from the database. Call at boot and after any
|
||||
/// admin change to a currency's rate/enabled state.
|
||||
pub async fn refresh_snapshot<C: sea_orm::ConnectionTrait>(db: &C) -> Result<()> {
|
||||
let rows = currencies::Entity::find()
|
||||
.filter(currencies::Column::Enabled.eq(true))
|
||||
.order_by_asc(currencies::Column::Code)
|
||||
.all(db)
|
||||
.await?;
|
||||
let list = rows
|
||||
.into_iter()
|
||||
.map(|m| Selectable {
|
||||
code: m.code,
|
||||
symbol: m.symbol,
|
||||
rate_e4: m.rate_e4,
|
||||
})
|
||||
.collect();
|
||||
*ENABLED.write().unwrap() = list;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The selectable currencies for templates (the Tera `currencies()` function):
|
||||
/// the EUR base plus every enabled alternative, each with a human rate string.
|
||||
/// `alts` is empty when the store is effectively EUR-only.
|
||||
#[must_use]
|
||||
pub fn selectable_json() -> serde_json::Value {
|
||||
let alts: Vec<serde_json::Value> = ENABLED
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|s| {
|
||||
serde_json::json!({
|
||||
"code": s.code,
|
||||
"symbol": s.symbol,
|
||||
"rate": format_rate(s.rate_e4),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
serde_json::json!({
|
||||
"base": { "code": BASE_CODE, "symbol": BASE_SYMBOL },
|
||||
"alts": alts,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse an exchange rate typed in major units ("25", "25.3", "25,30",
|
||||
/// "25.3045") into `rate_e4` (×10000). Rejects negatives and >4 decimals.
|
||||
pub fn parse_rate(value: &str) -> Result<i64> {
|
||||
|
||||
Reference in New Issue
Block a user