diff --git a/core/credit/src/disbursal/entity.rs b/core/credit/src/disbursal/entity.rs index 1094e0f9a..1d0e251db 100644 --- a/core/credit/src/disbursal/entity.rs +++ b/core/credit/src/disbursal/entity.rs @@ -18,7 +18,7 @@ pub enum DisbursalEvent { idx: DisbursalIdx, amount: UsdCents, account_ids: CreditFacilityAccountIds, - deposit_account_id: DepositAccountId, + deposit_account_id: uuid::Uuid, audit_info: AuditInfo, }, ApprovalProcessConcluded { @@ -45,7 +45,7 @@ pub struct Disbursal { pub idx: DisbursalIdx, pub amount: UsdCents, pub account_ids: CreditFacilityAccountIds, - pub deposit_account_id: DepositAccountId, + pub deposit_account_id: uuid::Uuid, #[builder(setter(strip_option), default)] pub concluded_tx_id: Option, pub(super) events: EntityEvents, @@ -182,7 +182,7 @@ pub struct NewDisbursal { pub(super) idx: DisbursalIdx, pub(super) amount: UsdCents, pub(super) account_ids: CreditFacilityAccountIds, - pub(super) deposit_account_id: DepositAccountId, + pub(super) deposit_account_id: uuid::Uuid, #[builder(setter(into))] pub(super) audit_info: AuditInfo, } diff --git a/core/credit/src/entity.rs b/core/credit/src/entity.rs index 0fb0877df..67c0e22cf 100644 --- a/core/credit/src/entity.rs +++ b/core/credit/src/entity.rs @@ -22,11 +22,11 @@ use super::{ pub enum CreditFacilityEvent { Initialized { id: CreditFacilityId, - customer_id: CustomerId, + credit_recipient_id: CreditRecipientId, terms: TermValues, facility: UsdCents, account_ids: CreditFacilityAccountIds, - deposit_account_id: DepositAccountId, + deposit_account_id: uuid::Uuid, approval_process_id: ApprovalProcessId, audit_info: AuditInfo, }, @@ -316,10 +316,10 @@ impl From<(InterestAccrualData, CreditFacilityAccountIds)> for CreditFacilityInt pub struct CreditFacility { pub id: CreditFacilityId, pub approval_process_id: ApprovalProcessId, - pub customer_id: CustomerId, + pub credit_recipient_id: CreditRecipientId, pub terms: TermValues, pub account_ids: CreditFacilityAccountIds, - pub deposit_account_id: DepositAccountId, + pub deposit_account_id: uuid::Uuid, #[builder(setter(strip_option), default)] pub activated_at: Option>, #[builder(setter(strip_option), default)] @@ -1114,7 +1114,7 @@ impl TryFromEvents for CreditFacility { match event { CreditFacilityEvent::Initialized { id, - customer_id, + credit_recipient_id, account_ids, deposit_account_id, terms: t, @@ -1124,7 +1124,7 @@ impl TryFromEvents for CreditFacility { terms = Some(*t); builder = builder .id(*id) - .customer_id(*customer_id) + .credit_recipient_id(*credit_recipient_id) .terms(*t) .account_ids(*account_ids) .deposit_account_id(*deposit_account_id) @@ -1160,7 +1160,7 @@ pub struct NewCreditFacility { #[builder(setter(into))] pub(super) approval_process_id: ApprovalProcessId, #[builder(setter(into))] - pub(super) customer_id: CustomerId, + pub(super) credit_recipient_id: CreditRecipientId, terms: TermValues, facility: UsdCents, #[builder(setter(skip), default)] @@ -1168,7 +1168,7 @@ pub struct NewCreditFacility { #[builder(setter(skip), default)] pub(super) collateralization_state: CollateralizationState, account_ids: CreditFacilityAccountIds, - deposit_account_id: DepositAccountId, + deposit_account_id: uuid::Uuid, #[builder(setter(into))] pub(super) audit_info: AuditInfo, } @@ -1186,7 +1186,7 @@ impl IntoEvents for NewCreditFacility { [CreditFacilityEvent::Initialized { id: self.id, audit_info: self.audit_info.clone(), - customer_id: self.customer_id, + credit_recipient_id: self.credit_recipient_id, terms: self.terms, facility: self.facility, account_ids: self.account_ids, @@ -1255,7 +1255,7 @@ mod test { vec![CreditFacilityEvent::Initialized { id: CreditFacilityId::new(), audit_info: dummy_audit_info(), - customer_id: CustomerId::new(), + credit_recipient_id: CustomerId::new(), facility: default_facility(), terms: default_terms(), account_ids: CreditFacilityAccountIds::new(), @@ -1940,11 +1940,11 @@ mod test { let new_credit_facility = NewCreditFacility::builder() .id(id) .approval_process_id(id) - .customer_id(CustomerId::new()) + .credit_recipient_id(CreditRecipientId::new()) .terms(default_terms()) .facility(UsdCents::from(1_000_000_00)) .account_ids(CreditFacilityAccountIds::new()) - .deposit_account_id(DepositAccountId::new()) + .deposit_account_id(uuid::Uuid::new_v4()) .audit_info(dummy_audit_info()) .build() .expect("could not build new credit facility"); diff --git a/core/credit/src/error.rs b/core/credit/src/error.rs index 5e9786532..3ceab2de2 100644 --- a/core/credit/src/error.rs +++ b/core/credit/src/error.rs @@ -32,10 +32,10 @@ pub enum CreditFacilityError { PaymentError(#[from] super::payment::error::PaymentError), #[error("CreditFacilityError - InterestAccrualError: {0}")] InterestAccrualError(#[from] super::interest_accrual::error::InterestAccrualError), - #[error("CreditFacilityError - DepositAccountForHolderNotFound: {0}")] - DepositAccountForHolderNotFound(DepositAccountHolderId), - #[error("CreditFacilityError - CoreDepositError: '{0}'")] - CoreDepositError(#[from] crate::deposit::error::CoreDepositError), + // #[error("CreditFacilityError - DepositAccountForHolderNotFound: {0}")] + // DepositAccountForHolderNotFound(DepositAccountHolderId), + // #[error("CreditFacilityError - CoreDepositError: '{0}'")] + // CoreDepositError(#[from] crate::deposit::error::CoreDepositError), #[error("CreditFacilityError - ApprovalInProgress")] ApprovalInProgress, #[error("CreditFacilityError - Denied")] @@ -68,14 +68,14 @@ pub enum CreditFacilityError { InterestAccrualWithInvalidFutureStartDate, #[error("CreditFacilityError - SubjectIsNotUser")] SubjectIsNotUser, - #[error("CreditFacilityError - SubjectIsNotCustomer")] - SubjectIsNotCustomer, + #[error("CreditFacilityError - SubjectIsNotCreditRecipientId")] + SubjectIsNotCreditRecipient, #[error( "CreditFacilityError - DisbursalAmountTooLarge: amount '{0}' is larger than facility balance '{1}'" )] DisbursalAmountTooLarge(UsdCents, UsdCents), - #[error("CreditFacilityError - CustomerMismatchForCreditFacility")] - CustomerMismatchForCreditFacility, + #[error("CreditFacilityError - CreditRecipientMismatchForCreditFacility")] + CreditRecipientMismatchForCreditFacility, } es_entity::from_es_entity_error!(CreditFacilityError); diff --git a/core/credit/src/for_subject.rs b/core/credit/src/for_subject.rs index 01f1945f4..93e204878 100644 --- a/core/credit/src/for_subject.rs +++ b/core/credit/src/for_subject.rs @@ -9,7 +9,7 @@ where Perms: PermissionCheck, E: OutboxEventMarker, { - customer_id: CustomerId, + credit_recipient_id: CreditRecipientId, subject: &'a <::Audit as AuditSvc>::Subject, authz: &'a Perms, credit_facilities: &'a CreditFacilityRepo, @@ -26,14 +26,14 @@ where { pub(super) fn new( subject: &'a <::Audit as AuditSvc>::Subject, - customer_id: CustomerId, + credit_recipient_id: CreditRecipientId, authz: &'a Perms, credit_facilities: &'a CreditFacilityRepo, disbursals: &'a DisbursalRepo, payments: &'a PaymentRepo, ) -> Self { Self { - customer_id, + credit_recipient_id, subject, authz, credit_facilities, @@ -61,7 +61,7 @@ where .await?; self.credit_facilities - .list_for_customer_id_by_created_at(self.customer_id, query, direction) + .list_for_credit_recipient_id_by_created_at(self.credit_recipient_id, query, direction) .await } @@ -108,12 +108,12 @@ where object: CoreCreditObject, action: CoreCreditAction, ) -> Result<(), CreditFacilityError> { - if credit_facility.customer_id != self.customer_id { + if credit_facility.credit_recipient_id != self.credit_recipient_id { self.authz .audit() .record_entry(self.subject, object, action, false) .await?; - return Err(CreditFacilityError::CustomerMismatchForCreditFacility); + return Err(CreditFacilityError::CreditRecipientMismatchForCreditFacility); } self.authz diff --git a/core/credit/src/ledger/credit_facility_accounts.rs b/core/credit/src/ledger/credit_facility_accounts.rs index e4fcc506e..89f80f5f3 100644 --- a/core/credit/src/ledger/credit_facility_accounts.rs +++ b/core/credit/src/ledger/credit_facility_accounts.rs @@ -2,11 +2,10 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use cala_ledger::AccountId as LedgerAccountId; -use chart_of_accounts::TransactionAccountFactory; +use chart_of_accounts::{CoreChartOfAccounts, TransactionAccountFactory}; use crate::{ - accounting_init::CreditFacilitiesAccountPaths, - chart_of_accounts::ChartOfAccounts, + // accounting_init::CreditFacilitiesAccountPaths, primitives::{LedgerTxId, Satoshis, UsdCents}, terms::InterestPeriod, }; @@ -47,28 +46,28 @@ pub struct CreditFacilityAccountFactories { pub fee_income: TransactionAccountFactory, } -impl CreditFacilityAccountFactories { - pub fn new( - chart_of_accounts: &ChartOfAccounts, - credit_facilities: CreditFacilitiesAccountPaths, - ) -> Self { - Self { - facility: chart_of_accounts.transaction_account_factory(credit_facilities.facility), - facility_omnibus: chart_of_accounts - .transaction_account_factory(credit_facilities.facility_omnibus), - disbursed_receivable: chart_of_accounts - .transaction_account_factory(credit_facilities.disbursed_receivable), - collateral: chart_of_accounts.transaction_account_factory(credit_facilities.collateral), - collateral_omnibus: chart_of_accounts - .transaction_account_factory(credit_facilities.collateral_omnibus), - interest_receivable: chart_of_accounts - .transaction_account_factory(credit_facilities.interest_receivable), - interest_income: chart_of_accounts - .transaction_account_factory(credit_facilities.interest_income), - fee_income: chart_of_accounts.transaction_account_factory(credit_facilities.fee_income), - } - } -} +// impl CreditFacilityAccountFactories { +// pub fn new( +// chart_of_accounts: &ChartOfAccounts, +// credit_facilities: CreditFacilitiesAccountPaths, +// ) -> Self { +// Self { +// facility: chart_of_accounts.transaction_account_factory(credit_facilities.facility), +// facility_omnibus: chart_of_accounts +// .transaction_account_factory(credit_facilities.facility_omnibus), +// disbursed_receivable: chart_of_accounts +// .transaction_account_factory(credit_facilities.disbursed_receivable), +// collateral: chart_of_accounts.transaction_account_factory(credit_facilities.collateral), +// collateral_omnibus: chart_of_accounts +// .transaction_account_factory(credit_facilities.collateral_omnibus), +// interest_receivable: chart_of_accounts +// .transaction_account_factory(credit_facilities.interest_receivable), +// interest_income: chart_of_accounts +// .transaction_account_factory(credit_facilities.interest_income), +// fee_income: chart_of_accounts.transaction_account_factory(credit_facilities.fee_income), +// } +// } +// } #[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct CreditFacilityLedgerBalance { pub facility: UsdCents, diff --git a/core/credit/src/ledger/velocity/disbursal_limit.rs b/core/credit/src/ledger/velocity/disbursal_limit.rs index a39517b1b..569dfa70f 100644 --- a/core/credit/src/ledger/velocity/disbursal_limit.rs +++ b/core/credit/src/ledger/velocity/disbursal_limit.rs @@ -10,7 +10,7 @@ impl DisbursalLimit { #[instrument(name = "ledger.disbursal_limit.init", skip_all)] pub async fn init( ledger: &CalaLedger, - ) -> Result { + ) -> Result { let limit = NewVelocityLimit::builder() .id(DISBURSAL_LIMIT_ID) .name("Disbursal Limit") diff --git a/core/credit/src/lib.rs b/core/credit/src/lib.rs index d240e2a2e..726541a75 100644 --- a/core/credit/src/lib.rs +++ b/core/credit/src/lib.rs @@ -224,13 +224,17 @@ where pub fn for_subject<'s>( &'s self, - sub: &<::Audit as AuditSvc>::Subject, - ) -> Result, CreditFacilityError> { - let customer_id = - CustomerId::try_from(sub).map_err(|_| CreditFacilityError::SubjectIsNotCustomer)?; + sub: &'s <::Audit as AuditSvc>::Subject, + ) -> Result, CreditFacilityError> + where + CreditRecipientId: + for<'a> TryFrom<&'a <::Audit as AuditSvc>::Subject>, + { + let credit_recipient_id = CreditRecipientId::try_from(sub) + .map_err(|_| CreditFacilityError::SubjectIsNotCreditRecipient)?; Ok(CreditFacilitiesForSubject::new( sub, - customer_id, + credit_recipient_id, &self.authz, &self.credit_facility_repo, &self.disbursal_repo, @@ -242,7 +246,10 @@ where pub async fn initiate( &self, sub: &<::Audit as AuditSvc>::Subject, - customer_id: impl Into + Into + std::fmt::Debug + Copy, + credit_recipient_id: impl Into + + Into + + std::fmt::Debug + + Copy, facility: UsdCents, terms: TermValues, ) -> Result { @@ -251,33 +258,15 @@ where .await? .expect("audit info missing"); - let deposit_accounts: Vec = self - .deposits - .list_accounts_by_created_at_for_account_holder( - sub, - customer_id, - Default::default(), - ListDirection::Descending, - ) - .await? - .entities - .into_iter() - .map(DepositAccount::from) - .collect(); - - let deposit_account = deposit_accounts.first().ok_or( - CreditFacilityError::DepositAccountForHolderNotFound(customer_id.into()), - )?; - let id = CreditFacilityId::new(); let new_credit_facility = NewCreditFacility::builder() .id(id) .approval_process_id(id) - .customer_id(customer_id) + .credit_recipient_id(credit_recipient_id) .terms(terms) .facility(facility) .account_ids(CreditFacilityAccountIds::new()) - .deposit_account_id(deposit_account.id) + .deposit_account_id(uuid::Uuid::new_v4()) .audit_info(audit_info.clone()) .build() .expect("could not build new credit facility"); diff --git a/core/credit/src/payment/entity.rs b/core/credit/src/payment/entity.rs index 85e652fbc..5c67e0953 100644 --- a/core/credit/src/payment/entity.rs +++ b/core/credit/src/payment/entity.rs @@ -18,7 +18,7 @@ pub enum PaymentEvent { facility_id: CreditFacilityId, amounts: CreditFacilityPaymentAmounts, account_ids: CreditFacilityAccountIds, - deposit_account_id: DepositAccountId, + deposit_account_id: uuid::Uuid, audit_info: AuditInfo, }, } @@ -32,7 +32,7 @@ pub struct Payment { pub facility_id: CreditFacilityId, pub amounts: CreditFacilityPaymentAmounts, pub account_ids: CreditFacilityAccountIds, - pub deposit_account_id: DepositAccountId, + pub deposit_account_id: uuid::Uuid, pub(super) events: EntityEvents, } @@ -87,7 +87,7 @@ pub struct NewPayment { pub(super) credit_facility_id: CreditFacilityId, pub(super) amounts: CreditFacilityPaymentAmounts, pub(super) account_ids: CreditFacilityAccountIds, - pub(super) deposit_account_id: DepositAccountId, + pub(super) deposit_account_id: uuid::Uuid, #[builder(setter(into))] pub(super) audit_info: AuditInfo, } diff --git a/core/credit/src/primitives.rs b/core/credit/src/primitives.rs index fde9beacb..3e14f6efa 100644 --- a/core/credit/src/primitives.rs +++ b/core/credit/src/primitives.rs @@ -14,20 +14,21 @@ pub use core_price::PriceOfOneBTC; pub use governance::ApprovalProcessId; es_entity::entity_id! { -CreditFacilityId, -DisbursalId, -PaymentId, -InterestAccrualId; + CreditFacilityId, + CreditRecipientId, + DisbursalId, + PaymentId, + InterestAccrualId; -CreditFacilityId => governance::ApprovalProcessId, -DisbursalId => governance::ApprovalProcessId, + CreditFacilityId => governance::ApprovalProcessId, + DisbursalId => governance::ApprovalProcessId, -CreditFacilityId => job::JobId, -InterestAccrualId => job::JobId, + CreditFacilityId => job::JobId, + InterestAccrualId => job::JobId, -DisbursalId => LedgerTxId, -PaymentId => LedgerTxId, + DisbursalId => LedgerTxId, + PaymentId => LedgerTxId, } pub type CreditFacilityAllOrOne = AllOrOne; diff --git a/core/credit/src/processes/activate_credit_facility/job.rs b/core/credit/src/processes/activate_credit_facility/job.rs index 1cb065c9b..b1c14ac35 100644 --- a/core/credit/src/processes/activate_credit_facility/job.rs +++ b/core/credit/src/processes/activate_credit_facility/job.rs @@ -122,7 +122,7 @@ where match message.as_ref().as_event() { Some(CoreCreditEvent::FacilityCollateralUpdated { id, .. }) | Some(CoreCreditEvent::FacilityApproved { id, .. }) => { - self.process.execute(id).await?; + self.process.execute(*id).await?; state.sequence = message.sequence; current_job.update_execution_state(state).await?; } diff --git a/core/credit/src/processes/approve_credit_facility/job.rs b/core/credit/src/processes/approve_credit_facility/job.rs index b751be4d8..b00eaea4e 100644 --- a/core/credit/src/processes/approve_credit_facility/job.rs +++ b/core/credit/src/processes/approve_credit_facility/job.rs @@ -137,7 +137,7 @@ where ref process_type, .. }) if process_type == &super::APPROVE_CREDIT_FACILITY_PROCESS => { - self.process.execute(id, approved).await?; + self.process.execute(*id, *approved).await?; state.sequence = message.sequence; current_job.update_execution_state(state).await?; } diff --git a/core/credit/src/processes/approve_disbursal/job.rs b/core/credit/src/processes/approve_disbursal/job.rs index 6c74baf06..0c4c4d464 100644 --- a/core/credit/src/processes/approve_disbursal/job.rs +++ b/core/credit/src/processes/approve_disbursal/job.rs @@ -137,7 +137,7 @@ where ref process_type, .. }) if process_type == &super::APPROVE_DISBURSAL_PROCESS => { - self.process.execute(id, approved).await?; + self.process.execute(*id, *approved).await?; state.sequence = message.sequence; current_job.update_execution_state(state).await?; } diff --git a/core/credit/src/repo.rs b/core/credit/src/repo.rs index 368d96d94..8f2c04e56 100644 --- a/core/credit/src/repo.rs +++ b/core/credit/src/repo.rs @@ -20,7 +20,7 @@ use super::{ entity = "CreditFacility", err = "CreditFacilityError", columns( - customer_id(ty = "CustomerId", list_for, update(persist = false)), + credit_recipient_id(ty = "CreditRecipientId", list_for, update(persist = false)), approval_process_id(ty = "ApprovalProcessId", list_by, update(persist = "false")), collateralization_ratio( ty = "Option", diff --git a/core/deposit/tests/withdraw.rs b/core/deposit/tests/withdraw.rs old mode 100644 new mode 100755 diff --git a/lana/app/migrations/20240517074612_core_setup.sql b/lana/app/migrations/20240517074612_core_setup.sql index 8d446ee2f..957d27558 100644 --- a/lana/app/migrations/20240517074612_core_setup.sql +++ b/lana/app/migrations/20240517074612_core_setup.sql @@ -162,7 +162,8 @@ CREATE TABLE user_events ( CREATE TABLE credit_facilities ( id UUID PRIMARY KEY, - customer_id UUID NOT NULL REFERENCES customers(id), + credit_recipient_id UUID NOT NULL REFERENCES customers(id), + customer_id UUID REFERENCES customers(id), approval_process_id UUID NOT NULL REFERENCES approval_processes(id), collateralization_ratio NUMERIC, collateralization_state VARCHAR NOT NULL,