use bevy::prelude::*;
use super::components::*;
use super::events::*;
use super::systems::*;
use crate::IssunSet;
#[derive(Default)]
pub struct AccountingPlugin {
pub config: AccountingConfig,
}
impl AccountingPlugin {
pub fn new() -> Self {
Self::default()
}
pub fn with_config(mut self, config: AccountingConfig) -> Self {
self.config = config;
self
}
pub fn with_period_days(mut self, days: u32) -> Self {
self.config.settlement_period_days = days;
self
}
}
impl Plugin for AccountingPlugin {
fn build(&self, app: &mut App) {
app.register_type::<AccountingConfig>()
.register_type::<BudgetLedger>()
.register_type::<SettlementHistory>()
.register_type::<SettlementSession>()
.register_type::<SettlementCalculation>()
.register_type::<SettlementRecord>()
.register_type::<IncomeSource>()
.register_type::<ExpenseItem>()
.register_type::<SettlementStatus>()
.register_type::<BudgetChannel>()
.register_type::<UniqueId>()
.register_type::<Organization>()
.register_type::<GameDay>()
.register_type::<SettlementRequested>()
.register_type::<SettlementCompletedEvent>()
.register_type::<BudgetTransferRequested>()
.register_type::<BudgetTransferredEvent>()
.register_type::<IncomeCalculationEvent>()
.register_type::<ExpenseCalculationEvent>();
app.insert_resource(self.config.clone());
app.insert_resource(GameDay::default());
app.add_message::<SettlementRequested>()
.add_message::<SettlementCompletedEvent>()
.add_message::<BudgetTransferRequested>()
.add_message::<BudgetTransferredEvent>();
app.add_systems(
Update,
handle_day_changed.in_set(IssunSet::Input),
);
app.add_systems(
Update,
(
start_settlement_sessions,
calculate_income,
calculate_expenses,
finalize_settlements,
)
.chain()
.in_set(IssunSet::Logic),
);
app.add_systems(
Update,
handle_budget_transfers.in_set(IssunSet::Logic),
);
app.add_systems(
Update,
cleanup_settlement_sessions.in_set(IssunSet::PostLogic),
);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::IssunCorePlugin;
#[test]
fn test_plugin_initialization() {
let mut app = App::new();
app.add_plugins(MinimalPlugins);
app.add_plugins(IssunCorePlugin);
app.add_plugins(AccountingPlugin::default());
assert!(app.world().get_resource::<AccountingConfig>().is_some());
assert!(app.world().get_resource::<GameDay>().is_some());
app.update();
}
#[test]
fn test_plugin_with_custom_config() {
let mut app = App::new();
app.add_plugins(MinimalPlugins);
app.add_plugins(IssunCorePlugin);
app.add_plugins(AccountingPlugin::new().with_config(AccountingConfig {
settlement_period_days: 30,
}));
let config = app.world().get_resource::<AccountingConfig>().unwrap();
assert_eq!(config.settlement_period_days, 30);
}
#[test]
fn test_basic_settlement_flow() {
let mut app = App::new();
app.add_plugins(MinimalPlugins);
app.add_plugins(IssunCorePlugin);
app.add_plugins(AccountingPlugin::default());
let org = app
.world_mut()
.spawn((
Organization {
name: "Player Corp".to_string(),
},
BudgetLedger::default(),
SettlementHistory::default(),
))
.id();
{
let mut day = app.world_mut().resource_mut::<GameDay>();
day.current = 7;
}
app.update();
let history = app.world().get::<SettlementHistory>(org).unwrap();
assert!(history.last_settlement_period > 0);
}
#[test]
fn test_budget_transfer_flow() {
let mut app = App::new();
app.add_plugins(MinimalPlugins);
app.add_plugins(IssunCorePlugin);
app.add_plugins(AccountingPlugin::default());
let org = app
.world_mut()
.spawn((
Organization {
name: "Test Corp".to_string(),
},
BudgetLedger::default(),
))
.id();
app.world_mut().write_message(BudgetTransferRequested {
organization: org,
from: BudgetChannel::Cash,
to: BudgetChannel::Research,
amount: Currency::new(500),
});
app.update();
let ledger = app.world().get::<BudgetLedger>(org).unwrap();
assert_eq!(ledger.cash, Currency::new(1900));
assert_eq!(ledger.research_pool, Currency::new(1100));
}
}