use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaxConfig {
pub base_amount: Decimal,
pub admin_fee: Decimal,
}
impl Default for TaxConfig {
fn default() -> Self {
Self {
base_amount: Decimal::ZERO,
admin_fee: dec!(120_000),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaxCalculator {
config: TaxConfig,
}
impl TaxCalculator {
pub fn new() -> Self {
Self::default()
}
pub fn with_config(config: TaxConfig) -> Self {
Self { config }
}
pub fn calculate(&self, pajak_input: Decimal) -> Decimal {
tracing::info!(
event = "calculate_tax",
pajak_input = %pajak_input,
admin_fee = %self.config.admin_fee,
"Calculating tax"
);
let total_pajak = pajak_input + self.config.admin_fee;
tracing::info!(
event = "tax_calculated",
total_pajak = %total_pajak,
"Tax calculated"
);
total_pajak
}
}
impl Default for TaxCalculator {
fn default() -> Self {
Self {
config: TaxConfig::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rust_decimal_macros::dec;
#[test]
fn test_tax_default_admin_fee() {
let calc = TaxCalculator::new();
let result = calc.calculate(dec!(100_000));
assert_eq!(result, dec!(220_000));
}
#[test]
fn test_tax_custom_admin_fee() {
let config = TaxConfig {
base_amount: dec!(0),
admin_fee: dec!(150_000),
};
let calc = TaxCalculator::with_config(config);
let result = calc.calculate(dec!(50_000));
assert_eq!(result, dec!(200_000));
}
#[test]
fn test_tax_zero_input() {
let calc = TaxCalculator::new();
let result = calc.calculate(dec!(0));
assert_eq!(result, dec!(120_000));
}
}