1use cala_types::{
2 account::*, account_set::*, balance::*, entry::*, journal::*, outbox::*, primitives::*,
3 transaction::*, tx_template::*,
4};
5use cel_interpreter::CelExpression;
6
7use crate::{client::proto, error::*};
8
9impl TryFrom<proto::CalaLedgerEvent> for obix::out::PersistentOutboxEvent<OutboxEventPayload> {
10 type Error = CalaLedgerOutboxClientError;
11
12 fn try_from(event: proto::CalaLedgerEvent) -> Result<Self, Self::Error> {
13 let payload = OutboxEventPayload::try_from(
14 event
15 .payload
16 .ok_or(CalaLedgerOutboxClientError::MissingField)?,
17 )?;
18 Ok(obix::out::PersistentOutboxEvent {
19 id: event.id.parse::<obix::out::OutboxEventId>()?,
20 sequence: obix::EventSequence::from(event.sequence),
21 payload: Some(payload),
22 tracing_context: None,
23 recorded_at: event
24 .recorded_at
25 .ok_or(CalaLedgerOutboxClientError::MissingField)?
26 .into(),
27 })
28 }
29}
30
31impl TryFrom<proto::cala_ledger_event::Payload> for OutboxEventPayload {
32 type Error = CalaLedgerOutboxClientError;
33
34 fn try_from(payload: proto::cala_ledger_event::Payload) -> Result<Self, Self::Error> {
35 use cala_types::outbox::OutboxEventPayload::*;
36 let res = match payload {
37 proto::cala_ledger_event::Payload::AccountCreated(proto::AccountCreated {
38 data_source_id,
39 account,
40 }) => AccountCreated {
41 source: data_source_id.parse()?,
42 account: AccountValues::try_from(
43 account.ok_or(CalaLedgerOutboxClientError::MissingField)?,
44 )?,
45 },
46 proto::cala_ledger_event::Payload::AccountUpdated(proto::AccountUpdated {
47 data_source_id,
48 account,
49 fields,
50 }) => AccountUpdated {
51 source: data_source_id.parse()?,
52 account: AccountValues::try_from(
53 account.ok_or(CalaLedgerOutboxClientError::MissingField)?,
54 )?,
55 fields,
56 },
57 proto::cala_ledger_event::Payload::AccountSetCreated(proto::AccountSetCreated {
58 data_source_id,
59 account_set,
60 }) => AccountSetCreated {
61 source: data_source_id.parse()?,
62 account_set: AccountSetValues::try_from(
63 account_set.ok_or(CalaLedgerOutboxClientError::MissingField)?,
64 )?,
65 },
66 proto::cala_ledger_event::Payload::AccountSetUpdated(proto::AccountSetUpdated {
67 data_source_id,
68 account_set,
69 fields,
70 }) => AccountSetUpdated {
71 source: data_source_id.parse()?,
72 account_set: AccountSetValues::try_from(
73 account_set.ok_or(CalaLedgerOutboxClientError::MissingField)?,
74 )?,
75 fields,
76 },
77 proto::cala_ledger_event::Payload::AccountSetMemberCreated(
78 proto::AccountSetMemberCreated {
79 data_source_id,
80 member,
81 },
82 ) => {
83 let member = member.ok_or(CalaLedgerOutboxClientError::MissingField)?;
84 AccountSetMemberCreated {
85 source: data_source_id.parse()?,
86 account_set_id: member.account_set_id.parse()?,
87 member_id: match member
88 .member
89 .ok_or(CalaLedgerOutboxClientError::MissingField)?
90 {
91 proto::account_set_member::Member::MemberAccountId(account_id) => {
92 cala_types::account_set::AccountSetMemberId::from(
93 account_id.parse::<AccountId>()?,
94 )
95 }
96 proto::account_set_member::Member::MemberAccountSetId(account_set_id) => {
97 cala_types::account_set::AccountSetMemberId::from(
98 account_set_id.parse::<AccountSetId>()?,
99 )
100 }
101 },
102 }
103 }
104 proto::cala_ledger_event::Payload::AccountSetMemberRemoved(
105 proto::AccountSetMemberRemoved {
106 data_source_id,
107 member,
108 },
109 ) => {
110 let member = member.ok_or(CalaLedgerOutboxClientError::MissingField)?;
111 AccountSetMemberRemoved {
112 source: data_source_id.parse()?,
113 account_set_id: member.account_set_id.parse()?,
114 member_id: match member
115 .member
116 .ok_or(CalaLedgerOutboxClientError::MissingField)?
117 {
118 proto::account_set_member::Member::MemberAccountId(account_id) => {
119 cala_types::account_set::AccountSetMemberId::from(
120 account_id.parse::<AccountId>()?,
121 )
122 }
123 proto::account_set_member::Member::MemberAccountSetId(account_set_id) => {
124 cala_types::account_set::AccountSetMemberId::from(
125 account_set_id.parse::<AccountSetId>()?,
126 )
127 }
128 },
129 }
130 }
131 proto::cala_ledger_event::Payload::JournalCreated(proto::JournalCreated {
132 data_source_id,
133 journal,
134 }) => JournalCreated {
135 source: data_source_id.parse()?,
136 journal: JournalValues::try_from(
137 journal.ok_or(CalaLedgerOutboxClientError::MissingField)?,
138 )?,
139 },
140 proto::cala_ledger_event::Payload::JournalUpdated(proto::JournalUpdated {
141 data_source_id,
142 journal,
143 fields,
144 }) => JournalUpdated {
145 source: data_source_id.parse()?,
146 journal: JournalValues::try_from(
147 journal.ok_or(CalaLedgerOutboxClientError::MissingField)?,
148 )?,
149 fields,
150 },
151 proto::cala_ledger_event::Payload::TxTemplateCreated(proto::TxTemplateCreated {
152 data_source_id,
153 tx_template,
154 }) => TxTemplateCreated {
155 source: data_source_id.parse()?,
156 tx_template: TxTemplateValues::try_from(
157 tx_template.ok_or(CalaLedgerOutboxClientError::MissingField)?,
158 )?,
159 },
160 proto::cala_ledger_event::Payload::TransactionCreated(proto::TransactionCreated {
161 data_source_id,
162 transaction,
163 }) => TransactionCreated {
164 source: data_source_id.parse()?,
165 transaction: TransactionValues::try_from(
166 transaction.ok_or(CalaLedgerOutboxClientError::MissingField)?,
167 )?,
168 },
169 proto::cala_ledger_event::Payload::TransactionUpdated(proto::TransactionUpdated {
170 data_source_id,
171 transaction,
172 fields,
173 }) => TransactionUpdated {
174 source: data_source_id.parse()?,
175 transaction: TransactionValues::try_from(
176 transaction.ok_or(CalaLedgerOutboxClientError::MissingField)?,
177 )?,
178 fields,
179 },
180 proto::cala_ledger_event::Payload::EntryCreated(proto::EntryCreated {
181 data_source_id,
182 entry,
183 }) => EntryCreated {
184 source: data_source_id.parse()?,
185 entry: EntryValues::try_from(
186 entry.ok_or(CalaLedgerOutboxClientError::MissingField)?,
187 )?,
188 },
189 proto::cala_ledger_event::Payload::BalanceCreated(proto::BalanceCreated {
190 data_source_id,
191 balance,
192 }) => BalanceCreated {
193 source: data_source_id.parse()?,
194 balance: BalanceSnapshot::try_from(
195 balance.ok_or(CalaLedgerOutboxClientError::MissingField)?,
196 )?,
197 },
198 proto::cala_ledger_event::Payload::BalanceUpdated(proto::BalanceUpdated {
199 data_source_id,
200 balance,
201 }) => BalanceUpdated {
202 source: data_source_id.parse()?,
203 balance: BalanceSnapshot::try_from(
204 balance.ok_or(CalaLedgerOutboxClientError::MissingField)?,
205 )?,
206 },
207
208 proto::cala_ledger_event::Payload::Empty(_) => Empty,
209 };
210 Ok(res)
211 }
212}
213
214impl TryFrom<proto::Account> for AccountValues {
215 type Error = CalaLedgerOutboxClientError;
216
217 fn try_from(account: proto::Account) -> Result<Self, Self::Error> {
218 let metadata = account.metadata.map(serde_json::to_value).transpose()?;
219 let normal_balance_type =
220 proto::DebitOrCredit::try_from(account.normal_balance_type).map(DebitOrCredit::from)?;
221 let status = proto::Status::try_from(account.status).map(Status::from)?;
222 let res = Self {
223 id: account.id.parse()?,
224 version: account.version,
225 code: account.code,
226 name: account.name,
227 external_id: account.external_id,
228 normal_balance_type,
229 status,
230 description: account.description,
231 metadata,
232 config: AccountConfig::from(
233 account
234 .config
235 .ok_or(CalaLedgerOutboxClientError::MissingField)?,
236 ),
237 };
238 Ok(res)
239 }
240}
241
242impl From<proto::AccountConfig> for AccountConfig {
243 fn from(config: proto::AccountConfig) -> Self {
244 Self {
245 is_account_set: config.is_account_set,
246 eventually_consistent: config.eventually_consistent,
247 }
248 }
249}
250
251impl TryFrom<proto::AccountSet> for AccountSetValues {
252 type Error = CalaLedgerOutboxClientError;
253
254 fn try_from(account_set: proto::AccountSet) -> Result<Self, Self::Error> {
255 let metadata = account_set.metadata.map(serde_json::to_value).transpose()?;
256 let normal_balance_type = proto::DebitOrCredit::try_from(account_set.normal_balance_type)
257 .map(DebitOrCredit::from)?;
258 let res = Self {
259 id: account_set.id.parse()?,
260 version: account_set.version,
261 journal_id: account_set.journal_id.parse()?,
262 name: account_set.name,
263 external_id: account_set.external_id,
264 normal_balance_type,
265 description: account_set.description,
266 metadata,
267 };
268 Ok(res)
269 }
270}
271
272impl TryFrom<proto::Journal> for JournalValues {
273 type Error = CalaLedgerOutboxClientError;
274
275 fn try_from(journal: proto::Journal) -> Result<Self, Self::Error> {
276 let status = proto::Status::try_from(journal.status).map(Status::from)?;
277 let res = Self {
278 id: journal.id.parse()?,
279 version: journal.version,
280 name: journal.name,
281 code: journal.code,
282 status,
283 description: journal.description,
284 config: JournalConfig::from(
285 journal
286 .config
287 .ok_or(CalaLedgerOutboxClientError::MissingField)?,
288 ),
289 };
290 Ok(res)
291 }
292}
293
294impl From<proto::JournalConfig> for JournalConfig {
295 fn from(config: proto::JournalConfig) -> Self {
296 Self {
297 enable_effective_balances: config.enable_effective_balances,
298 }
299 }
300}
301
302impl From<proto::DebitOrCredit> for DebitOrCredit {
303 fn from(dc: proto::DebitOrCredit) -> Self {
304 match dc {
305 proto::DebitOrCredit::Debit => DebitOrCredit::Debit,
306 proto::DebitOrCredit::Credit => DebitOrCredit::Credit,
307 }
308 }
309}
310
311impl From<proto::Status> for Status {
312 fn from(status: proto::Status) -> Self {
313 match status {
314 proto::Status::Active => Status::Active,
315 proto::Status::Locked => Status::Locked,
316 }
317 }
318}
319
320impl TryFrom<proto::TxTemplate> for TxTemplateValues {
321 type Error = CalaLedgerOutboxClientError;
322
323 fn try_from(
324 proto::TxTemplate {
325 id,
326 version,
327 code,
328 params,
329 transaction,
330 entries,
331 description,
332 metadata,
333 }: proto::TxTemplate,
334 ) -> Result<Self, Self::Error> {
335 let params = params
336 .into_iter()
337 .map(ParamDefinition::try_from)
338 .collect::<Result<Vec<_>, _>>()?;
339 let transaction = TxTemplateTransaction::try_from(
340 transaction.ok_or(CalaLedgerOutboxClientError::MissingField)?,
341 )?;
342 let entries = entries
343 .into_iter()
344 .map(TxTemplateEntry::try_from)
345 .collect::<Result<Vec<_>, _>>()?;
346
347 let res = Self {
348 id: id.parse()?,
349 version,
350 code,
351 params: Some(params),
352 transaction,
353 entries,
354 description,
355 metadata: metadata.map(serde_json::to_value).transpose()?,
356 };
357 Ok(res)
358 }
359}
360
361impl TryFrom<proto::ParamDefinition> for ParamDefinition {
362 type Error = CalaLedgerOutboxClientError;
363 fn try_from(
364 proto::ParamDefinition {
365 name,
366 data_type,
367 default,
368 description,
369 }: proto::ParamDefinition,
370 ) -> Result<Self, Self::Error> {
371 let res = Self {
372 name,
373 r#type: proto::ParamDataType::try_from(data_type).map(ParamDataType::from)?,
374 default: default.map(CelExpression::try_from).transpose()?,
375 description,
376 };
377 Ok(res)
378 }
379}
380
381impl TryFrom<proto::TxTemplateTransaction> for TxTemplateTransaction {
382 type Error = CalaLedgerOutboxClientError;
383 fn try_from(
384 proto::TxTemplateTransaction {
385 effective,
386 journal_id,
387 correlation_id,
388 external_id,
389 description,
390 metadata,
391 }: proto::TxTemplateTransaction,
392 ) -> Result<Self, Self::Error> {
393 let res = Self {
394 effective: CelExpression::try_from(effective)?,
395 journal_id: CelExpression::try_from(journal_id)?,
396 correlation_id: correlation_id.map(CelExpression::try_from).transpose()?,
397 external_id: external_id.map(CelExpression::try_from).transpose()?,
398 description: description.map(CelExpression::try_from).transpose()?,
399 metadata: metadata.map(CelExpression::try_from).transpose()?,
400 };
401 Ok(res)
402 }
403}
404
405impl TryFrom<proto::TxTemplateEntry> for TxTemplateEntry {
406 type Error = CalaLedgerOutboxClientError;
407 fn try_from(
408 proto::TxTemplateEntry {
409 entry_type,
410 account_id,
411 layer,
412 direction,
413 units,
414 currency,
415 description,
416 metadata,
417 }: proto::TxTemplateEntry,
418 ) -> Result<Self, Self::Error> {
419 let res = Self {
420 entry_type: CelExpression::try_from(entry_type)?,
421 account_id: CelExpression::try_from(account_id)?,
422 layer: CelExpression::try_from(layer)?,
423 direction: CelExpression::try_from(direction)?,
424 units: CelExpression::try_from(units)?,
425 currency: CelExpression::try_from(currency)?,
426 description: description.map(CelExpression::try_from).transpose()?,
427 metadata: metadata.map(CelExpression::try_from).transpose()?,
428 };
429 Ok(res)
430 }
431}
432
433impl From<proto::ParamDataType> for ParamDataType {
434 fn from(data_type: proto::ParamDataType) -> Self {
435 match data_type {
436 proto::ParamDataType::String => ParamDataType::String,
437 proto::ParamDataType::Integer => ParamDataType::Integer,
438 proto::ParamDataType::Decimal => ParamDataType::Decimal,
439 proto::ParamDataType::Boolean => ParamDataType::Boolean,
440 proto::ParamDataType::Uuid => ParamDataType::Uuid,
441 proto::ParamDataType::Date => ParamDataType::Date,
442 proto::ParamDataType::Timestamp => ParamDataType::Timestamp,
443 proto::ParamDataType::Json => ParamDataType::Json,
444 }
445 }
446}
447
448impl TryFrom<proto::Transaction> for TransactionValues {
449 type Error = CalaLedgerOutboxClientError;
450 fn try_from(
451 proto::Transaction {
452 id,
453 version,
454 created_at,
455 modified_at,
456 journal_id,
457 tx_template_id,
458 entry_ids,
459 effective,
460 correlation_id,
461 external_id,
462 description,
463 metadata,
464 void_of,
465 voided_by,
466 }: proto::Transaction,
467 ) -> Result<Self, Self::Error> {
468 let res = Self {
469 id: id.parse()?,
470 version,
471 created_at: created_at
472 .ok_or(CalaLedgerOutboxClientError::MissingField)?
473 .into(),
474 modified_at: modified_at
475 .ok_or(CalaLedgerOutboxClientError::MissingField)?
476 .into(),
477 journal_id: journal_id.parse()?,
478 tx_template_id: tx_template_id.parse()?,
479 entry_ids: entry_ids
480 .into_iter()
481 .map(|id| id.parse())
482 .collect::<Result<_, _>>()?,
483 effective: effective.parse()?,
484 voided_by: voided_by.map(|id| id.parse()).transpose()?,
485 void_of: void_of.map(|id| id.parse()).transpose()?,
486 correlation_id,
487 external_id,
488 description,
489 metadata: metadata.map(serde_json::to_value).transpose()?,
490 };
491 Ok(res)
492 }
493}
494
495impl TryFrom<proto::Entry> for EntryValues {
496 type Error = CalaLedgerOutboxClientError;
497 fn try_from(
498 proto::Entry {
499 id,
500 version,
501 journal_id,
502 transaction_id,
503 entry_type,
504 sequence,
505 account_id,
506 layer,
507 direction,
508 units,
509 currency,
510 description,
511 metadata,
512 }: proto::Entry,
513 ) -> Result<Self, Self::Error> {
514 let res = Self {
515 id: id.parse()?,
516 version,
517 journal_id: journal_id.parse()?,
518 transaction_id: transaction_id.parse()?,
519 account_id: account_id.parse()?,
520 entry_type,
521 sequence,
522 layer: proto::Layer::try_from(layer).map(Layer::from)?,
523 direction: proto::DebitOrCredit::try_from(direction).map(DebitOrCredit::from)?,
524 units: units.parse()?,
525 currency: currency.parse::<Currency>()?,
526 description,
527 metadata: metadata.map(serde_json::to_value).transpose()?,
528 };
529 Ok(res)
530 }
531}
532
533impl TryFrom<proto::Balance> for BalanceSnapshot {
534 type Error = CalaLedgerOutboxClientError;
535 fn try_from(
536 proto::Balance {
537 journal_id,
538 account_id,
539 currency,
540 version,
541 created_at,
542 modified_at,
543 entry_id,
544 settled,
545 pending,
546 encumbrance,
547 }: proto::Balance,
548 ) -> Result<Self, Self::Error> {
549 let res = Self {
550 journal_id: journal_id.parse()?,
551 account_id: account_id.parse()?,
552 currency: currency.parse()?,
553 version,
554 created_at: created_at
555 .ok_or(CalaLedgerOutboxClientError::MissingField)?
556 .into(),
557 modified_at: modified_at
558 .ok_or(CalaLedgerOutboxClientError::MissingField)?
559 .into(),
560 entry_id: entry_id.parse()?,
561 settled: BalanceAmount::try_from(
562 settled.ok_or(CalaLedgerOutboxClientError::MissingField)?,
563 )?,
564 pending: BalanceAmount::try_from(
565 pending.ok_or(CalaLedgerOutboxClientError::MissingField)?,
566 )?,
567 encumbrance: BalanceAmount::try_from(
568 encumbrance.ok_or(CalaLedgerOutboxClientError::MissingField)?,
569 )?,
570 };
571 Ok(res)
572 }
573}
574
575impl TryFrom<proto::BalanceAmount> for BalanceAmount {
576 type Error = CalaLedgerOutboxClientError;
577
578 fn try_from(amount: proto::BalanceAmount) -> Result<Self, Self::Error> {
579 let res = Self {
580 dr_balance: amount.dr_balance.parse()?,
581 cr_balance: amount.cr_balance.parse()?,
582 entry_id: amount.entry_id.parse()?,
583 modified_at: amount
584 .modified_at
585 .ok_or(CalaLedgerOutboxClientError::MissingField)?
586 .into(),
587 };
588 Ok(res)
589 }
590}
591
592impl From<proto::Layer> for Layer {
593 fn from(layer: proto::Layer) -> Self {
594 match layer {
595 proto::Layer::Settled => Layer::Settled,
596 proto::Layer::Pending => Layer::Pending,
597 proto::Layer::Encumbrance => Layer::Encumbrance,
598 }
599 }
600}