use rust_decimal::Decimal;
use datasynth_core::models::journal_entry::{JournalEntry, JournalEntryHeader, JournalEntryLine};
use crate::config::IcTransactionType;
use crate::shard::ic_plan::{IcPairPlan, IcRole};
#[derive(Debug, Clone)]
pub struct InjectionCtx {
pub entity_code: String,
}
pub fn inject_ic_journal_entries(plans: &[IcPairPlan], ctx: &InjectionCtx) -> Vec<JournalEntry> {
plans
.iter()
.map(|plan| build_je_for_plan(plan, ctx))
.collect()
}
pub fn seller_accounts(t: IcTransactionType) -> (&'static str, &'static str) {
match t {
IcTransactionType::GoodsSale
| IcTransactionType::ServiceProvided
| IcTransactionType::ManagementFee
| IcTransactionType::Royalty
| IcTransactionType::CostSharing
| IcTransactionType::ExpenseRecharge => ("1150", "4500"),
IcTransactionType::LoanInterest => ("1150", "7000"),
IcTransactionType::Dividend => ("1000", "4900"),
}
}
pub fn buyer_accounts(t: IcTransactionType) -> (&'static str, &'static str) {
match t {
IcTransactionType::GoodsSale => ("5000", "2050"),
IcTransactionType::ServiceProvided
| IcTransactionType::ManagementFee
| IcTransactionType::Royalty
| IcTransactionType::CostSharing
| IcTransactionType::ExpenseRecharge => ("6800", "2050"),
IcTransactionType::LoanInterest => ("7100", "2050"),
IcTransactionType::Dividend => ("1000", "2050"),
}
}
fn build_je_for_plan(plan: &IcPairPlan, ctx: &InjectionCtx) -> JournalEntry {
let (dr_acct, cr_acct) = match plan.role {
IcRole::Seller => seller_accounts(plan.transaction_type),
IcRole::Buyer => buyer_accounts(plan.transaction_type),
};
let mut header = JournalEntryHeader::new(ctx.entity_code.clone(), plan.date);
header.ic_pair_id = Some(plan.pair_id);
header.ic_partner_entity = Some(plan.partner_entity.clone());
let (from, to) = match plan.role {
IcRole::Seller => (&ctx.entity_code, &plan.partner_entity),
IcRole::Buyer => (&plan.partner_entity, &ctx.entity_code),
};
header.header_text = Some(format!(
"IC {:?}: {} \u{2192} {} (pair {})",
plan.transaction_type, from, to, plan.index,
));
let mut je = JournalEntry::new(header);
let doc_id = je.header.document_id;
let amount: Decimal = plan.amount;
je.add_line(JournalEntryLine::debit(
doc_id,
1,
dr_acct.to_string(),
amount,
));
je.add_line(JournalEntryLine::credit(
doc_id,
2,
cr_acct.to_string(),
amount,
));
je
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn seller_accounts_covers_all_variants() {
assert_eq!(
seller_accounts(IcTransactionType::GoodsSale),
("1150", "4500")
);
assert_eq!(
seller_accounts(IcTransactionType::ServiceProvided),
("1150", "4500")
);
assert_eq!(
seller_accounts(IcTransactionType::ManagementFee),
("1150", "4500")
);
assert_eq!(
seller_accounts(IcTransactionType::Royalty),
("1150", "4500")
);
assert_eq!(
seller_accounts(IcTransactionType::CostSharing),
("1150", "4500")
);
assert_eq!(
seller_accounts(IcTransactionType::ExpenseRecharge),
("1150", "4500")
);
assert_eq!(
seller_accounts(IcTransactionType::LoanInterest),
("1150", "7000")
);
assert_eq!(
seller_accounts(IcTransactionType::Dividend),
("1000", "4900")
);
}
#[test]
fn buyer_accounts_covers_all_variants() {
assert_eq!(
buyer_accounts(IcTransactionType::GoodsSale),
("5000", "2050")
);
assert_eq!(
buyer_accounts(IcTransactionType::ServiceProvided),
("6800", "2050")
);
assert_eq!(
buyer_accounts(IcTransactionType::ManagementFee),
("6800", "2050")
);
assert_eq!(buyer_accounts(IcTransactionType::Royalty), ("6800", "2050"));
assert_eq!(
buyer_accounts(IcTransactionType::CostSharing),
("6800", "2050")
);
assert_eq!(
buyer_accounts(IcTransactionType::ExpenseRecharge),
("6800", "2050")
);
assert_eq!(
buyer_accounts(IcTransactionType::LoanInterest),
("7100", "2050")
);
assert_eq!(
buyer_accounts(IcTransactionType::Dividend),
("1000", "2050")
);
}
}