backbone_maintenance/application/service/
maintenance_gl.rs1use rust_decimal::Decimal;
11use serde::{Deserialize, Serialize};
12use uuid::Uuid;
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16pub struct GlPostLine {
17 pub account_id: Uuid,
18 pub debit: Decimal,
19 pub credit: Decimal,
20 pub party_type: Option<String>,
21 pub party_id: Option<Uuid>,
22 pub description: Option<String>,
23}
24
25impl GlPostLine {
26 pub fn debit(account_id: Uuid, amount: Decimal) -> Self {
27 Self { account_id, debit: amount, credit: Decimal::ZERO, party_type: None, party_id: None, description: None }
28 }
29 pub fn credit(account_id: Uuid, amount: Decimal) -> Self {
30 Self { account_id, debit: Decimal::ZERO, credit: amount, party_type: None, party_id: None, description: None }
31 }
32 pub fn with_description(mut self, d: impl Into<String>) -> Self {
33 self.description = Some(d.into());
34 self
35 }
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
40pub struct AccountingPostEnvelope {
41 pub idempotency_key: String,
42 pub company_id: Uuid,
45 pub branch_id: Option<Uuid>,
46 pub source_type: String,
49 pub source_id: Uuid,
52 pub source_reference: Option<String>,
53 pub posting_date: chrono::NaiveDate,
54 pub currency: String,
55 pub posting_type: String,
57 pub description: Option<String>,
58 pub lines: Vec<GlPostLine>,
59}
60
61impl AccountingPostEnvelope {
62 pub fn totals(&self) -> (Decimal, Decimal) {
63 (
64 self.lines.iter().map(|l| l.debit).sum(),
65 self.lines.iter().map(|l| l.credit).sum(),
66 )
67 }
68 pub fn is_balanced(&self) -> bool {
69 let (d, c) = self.totals();
70 d == c && !self.lines.is_empty()
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
76pub struct GlPostAck {
77 pub post_id: Uuid,
78 pub journal_id: Uuid,
79 pub idempotent_reuse: bool,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
84pub struct GlPostRejected {
85 pub code: String,
86 pub message: String,
87}
88
89#[async_trait::async_trait]
91pub trait GlPostSink: Send + Sync {
92 async fn post(&self, envelope: &AccountingPostEnvelope) -> Result<GlPostAck, GlPostRejected>;
93}