Skip to content

Commit

Permalink
feat: cancel and confirm disbursal templates
Browse files Browse the repository at this point in the history
  • Loading branch information
thevaibhav-dixit committed Jan 20, 2025
1 parent 6742782 commit ef5a216
Show file tree
Hide file tree
Showing 10 changed files with 523 additions and 45 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 65 additions & 4 deletions lana/app/src/credit_facility/ledger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ impl CreditLedger {
templates::RecordPayment::init(cala).await?;
templates::CreditFacilityIncurInterest::init(cala).await?;
templates::CreditFacilityAccrueInterest::init(cala).await?;
templates::CreditFacilityDisbursal::init(cala).await?;
templates::InitiateDisbursal::init(cala).await?;
templates::CancelDisbursal::init(cala).await?;
templates::ConfirmDisbursal::init(cala).await?;

let disbursal_limit_id = velocity::DisbursalLimit::init(cala).await?;

Expand Down Expand Up @@ -362,7 +364,7 @@ impl CreditLedger {
Ok(())
}

pub async fn record_disbursal(
pub async fn confirm_disbursal(
&self,
op: es_entity::DbOp<'_>,
DisbursalData {
Expand All @@ -378,8 +380,8 @@ impl CreditLedger {
.post_transaction_in_op(
&mut op,
tx_id,
templates::CREDIT_FACILITY_DISBURSAL_CODE,
templates::CreditFacilityDisbursalParams {
templates::CONFIRM_DISBURSAL_CODE,
templates::ConfirmDisbursalParams {
journal_id: self.journal_id,
credit_omnibus_account: self.credit_omnibus_account,
credit_facility_account: credit_facility_account_ids.facility_account_id,
Expand All @@ -395,6 +397,65 @@ impl CreditLedger {
Ok(())
}

pub async fn cancel_disbursal(
&self,
op: es_entity::DbOp<'_>,
amount: UsdCents,
credit_facility_account_ids: CreditFacilityAccountIds,
debit_account_id: impl Into<AccountId>,
) -> Result<(), CreditLedgerError> {
let mut op = self.cala.ledger_operation_from_db_op(op);

let tx_id = cala_ledger::TransactionId::new();
self.cala
.post_transaction_in_op(
&mut op,
tx_id,
templates::CANCEL_DISBURSAL_CODE,
templates::CancelDisbursalParams {
journal_id: self.journal_id,
credit_omnibus_account: self.credit_omnibus_account,
credit_facility_account: credit_facility_account_ids.facility_account_id,
facility_disbursed_receivable_account: credit_facility_account_ids
.disbursed_receivable_account_id,
checking_account: debit_account_id.into(),
disbursed_amount: amount.to_usd(),
},
)
.await?;
op.commit().await?;
Ok(())
}

pub async fn initiate_disbursal(
&self,
op: es_entity::DbOp<'_>,
tx_id: impl Into<TransactionId>,
amount: UsdCents,
credit_facility_account_ids: CreditFacilityAccountIds,
debit_account_id: impl Into<AccountId>,
) -> Result<(), CreditLedgerError> {
let mut op = self.cala.ledger_operation_from_db_op(op);
self.cala
.post_transaction_in_op(
&mut op,
tx_id.into(),
templates::INITIATE_DISBURSAL_CODE,
templates::InitiateDisbursalParams {
journal_id: self.journal_id,
credit_omnibus_account: self.credit_omnibus_account,
credit_facility_account: credit_facility_account_ids.facility_account_id,
facility_disbursed_receivable_account: credit_facility_account_ids
.disbursed_receivable_account_id,
checking_account: debit_account_id.into(),
disbursed_amount: amount.to_usd(),
},
)
.await?;
op.commit().await?;
Ok(())
}

async fn create_bank_collateral_account(
cala: &CalaLedger,
encoded_path: String,
Expand Down
194 changes: 194 additions & 0 deletions lana/app/src/credit_facility/ledger/templates/cancel_disbursal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
use crate::credit_facility::ledger::error::*;
use cala_ledger::{
tx_template::{error::TxTemplateError, Params, *},
*,
};
use rust_decimal::Decimal;
use tracing::instrument;

pub const CANCEL_DISBURSAL_CODE: &str = "CANCEL_DISBURSAL_CODE";

#[derive(Debug)]
pub struct CancelDisbursalParams {
pub journal_id: JournalId,
pub credit_omnibus_account: AccountId,
pub credit_facility_account: AccountId,
pub facility_disbursed_receivable_account: AccountId,
pub checking_account: AccountId,
pub disbursed_amount: Decimal,
}

impl CancelDisbursalParams {
pub fn defs() -> Vec<NewParamDefinition> {
vec![
NewParamDefinition::builder()
.name("journal_id")
.r#type(ParamDataType::Uuid)
.build()
.unwrap(),
NewParamDefinition::builder()
.name("credit_omnibus_account")
.r#type(ParamDataType::Uuid)
.build()
.unwrap(),
NewParamDefinition::builder()
.name("credit_facility_account")
.r#type(ParamDataType::Uuid)
.build()
.unwrap(),
NewParamDefinition::builder()
.name("facility_disbursed_receivable_account")
.r#type(ParamDataType::Uuid)
.build()
.unwrap(),
NewParamDefinition::builder()
.name("checking_account")
.r#type(ParamDataType::Uuid)
.build()
.unwrap(),
NewParamDefinition::builder()
.name("disbursed_amount")
.r#type(ParamDataType::Decimal)
.build()
.unwrap(),
NewParamDefinition::builder()
.name("effective")
.r#type(ParamDataType::Date)
.build()
.unwrap(),
]
}
}

impl From<CancelDisbursalParams> for Params {
fn from(
CancelDisbursalParams {
journal_id,
credit_omnibus_account,
credit_facility_account,
facility_disbursed_receivable_account,
checking_account,
disbursed_amount,
}: CancelDisbursalParams,
) -> Self {
let mut params = Self::default();
params.insert("journal_id", journal_id);
params.insert("credit_omnibus_account", credit_omnibus_account);
params.insert("credit_facility_account", credit_facility_account);
params.insert(
"facility_disbursed_receivable_account",
facility_disbursed_receivable_account,
);
params.insert("checking_account", checking_account);
params.insert("disbursed_amount", disbursed_amount);
params.insert("effective", chrono::Utc::now().date_naive());
params
}
}

pub struct CancelDisbursal;

impl CancelDisbursal {
#[instrument(name = "ledger.cancel_disbursal.init", skip_all)]
pub async fn init(ledger: &CalaLedger) -> Result<(), CreditLedgerError> {
let tx_input = NewTxTemplateTransaction::builder()
.journal_id("params.journal_id")
.effective("params.effective")
.description("'Cancel a disbursal'")
.build()
.expect("Couldn't build TxInput");

let entries = vec![
// Reverse pending entries
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_DRAWDOWN_PENDING_DR'")
.currency("'USD'")
.account_id("params.credit_omnibus_account")
.direction("DEBIT")
.layer("PENDING")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_DRAWDOWN_PENDING_CR'")
.currency("'USD'")
.account_id("params.credit_facility_account")
.direction("CREDIT")
.layer("PENDING")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_PENDING_DR'")
.currency("'USD'")
.account_id("params.facility_disbursed_receivable_account")
.direction("DEBIT")
.layer("PENDING")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_PENDING_CR'")
.currency("'USD'")
.account_id("params.checking_account")
.direction("CREDIT")
.layer("PENDING")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
// Reverse settled entries
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_DRAWDOWN_SETTLED_CR'")
.currency("'USD'")
.account_id("params.credit_omnibus_account")
.direction("CREDIT")
.layer("SETTLED")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_DRAWDOWN_SETTLED_DR'")
.currency("'USD'")
.account_id("params.credit_facility_account")
.direction("DEBIT")
.layer("SETTLED")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_SETTLED_CR'")
.currency("'USD'")
.account_id("params.facility_disbursed_receivable_account")
.direction("CREDIT")
.layer("SETTLED")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
NewTxTemplateEntry::builder()
.entry_type("'CANCEL_DISBURSAL_SETTLED_DR'")
.currency("'USD'")
.account_id("params.checking_account")
.direction("DEBIT")
.layer("SETTLED")
.units("params.disbursed_amount")
.build()
.expect("Couldn't build entry"),
];

let params = CancelDisbursalParams::defs();
let template = NewTxTemplate::builder()
.id(TxTemplateId::new())
.code(CANCEL_DISBURSAL_CODE)
.transaction(tx_input)
.entries(entries)
.params(params)
.build()
.expect("Couldn't build template");

match ledger.tx_templates().create(template).await {
Err(TxTemplateError::DuplicateCode) => Ok(()),
Err(e) => Err(e.into()),
Ok(_) => Ok(()),
}
}
}
Loading

0 comments on commit ef5a216

Please sign in to comment.