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