use datasynth_core::models::intercompany::EliminationEntry;
use datasynth_core::models::{
BusinessProcess, JournalEntry, JournalEntryHeader, JournalEntryLine, TransactionSource,
};
pub fn elimination_to_journal_entries(entries: &[EliminationEntry]) -> Vec<JournalEntry> {
entries
.iter()
.filter_map(|elim| {
if !elim.is_balanced() {
return None;
}
let mut header =
JournalEntryHeader::new(elim.consolidation_entity.clone(), elim.entry_date);
header.document_type = "ELIMINATION".to_string();
header.created_by = "CONSOLIDATION".to_string();
header.user_persona = "system_consolidation".to_string();
header.currency = elim.currency.clone();
header.source = TransactionSource::Automated;
header.business_process = Some(BusinessProcess::R2R);
header.header_text = Some(elim.description.clone());
header.reference = Some(elim.entry_id.clone());
header.is_elimination = true;
if elim.fiscal_period.len() == 6 {
if let (Ok(year), Ok(month)) = (
elim.fiscal_period[..4].parse::<u16>(),
elim.fiscal_period[4..].parse::<u8>(),
) {
header.fiscal_year = year;
header.fiscal_period = month;
}
}
let document_id = header.document_id;
let mut je = JournalEntry::new(header);
for (idx, line) in elim.lines.iter().enumerate() {
let line_number = (idx as u32) + 1;
let je_line = if line.is_debit {
JournalEntryLine::debit(
document_id,
line_number,
line.account.clone(),
line.amount,
)
} else {
JournalEntryLine::credit(
document_id,
line_number,
line.account.clone(),
line.amount,
)
};
je.add_line(je_line);
}
Some(je)
})
.collect()
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use chrono::NaiveDate;
use datasynth_core::models::intercompany::EliminationEntry;
use rust_decimal_macros::dec;
fn sample_ic_balance_elim() -> EliminationEntry {
EliminationEntry::create_ic_balance_elimination(
"ELIM001".to_string(),
"GROUP".to_string(),
"202406".to_string(),
NaiveDate::from_ymd_opt(2024, 6, 30).unwrap(),
"C001",
"C002",
"1310", "2110", dec!(50000),
"USD".to_string(),
)
}
#[test]
fn test_converts_balanced_elimination() {
let elim = sample_ic_balance_elim();
let jes = elimination_to_journal_entries(&[elim]);
assert_eq!(jes.len(), 1);
let je = &jes[0];
assert!(je.is_balanced(), "Resulting JE must be balanced");
assert_eq!(je.header.document_type, "ELIMINATION");
assert_eq!(je.header.created_by, "CONSOLIDATION");
assert!(je.header.is_elimination);
assert_eq!(je.line_count(), 2);
}
#[test]
fn test_fiscal_period_parsed() {
let elim = sample_ic_balance_elim();
let jes = elimination_to_journal_entries(&[elim]);
let je = &jes[0];
assert_eq!(je.header.fiscal_year, 2024);
assert_eq!(je.header.fiscal_period, 6);
}
#[test]
fn test_empty_slice_returns_empty() {
let jes = elimination_to_journal_entries(&[]);
assert!(jes.is_empty());
}
#[test]
fn test_multiple_entries_converted() {
let e1 = sample_ic_balance_elim();
let e2 = EliminationEntry::create_ic_revenue_expense_elimination(
"ELIM002".to_string(),
"GROUP".to_string(),
"202406".to_string(),
NaiveDate::from_ymd_opt(2024, 6, 30).unwrap(),
"C001",
"C002",
"4100", "5100", dec!(120000),
"USD".to_string(),
);
let jes = elimination_to_journal_entries(&[e1, e2]);
assert_eq!(jes.len(), 2);
for je in &jes {
assert!(je.is_balanced());
assert!(je.header.is_elimination);
}
}
}