Skip to main content

backbone_accounting/
lib.rs

1//! Accounting Module
2//!
3//! Generated by metaphor-schema. Enhanced with runtime implementations.
4//!
5//! This module provides:
6//! - Domain entities and repositories
7//! - Application services
8//! - HTTP and gRPC handlers
9//! - Route configuration
10//! - State machine enforcement
11//! - Validation rules runtime
12//! - RBAC middleware
13//! - Trigger execution system
14//! - Computed fields
15//! - Workflow orchestrator
16
17#![recursion_limit = "1024"]
18#![allow(unused_imports)]
19
20// Generated modules
21pub mod domain;
22pub mod infrastructure;
23pub mod application;
24pub mod presentation;
25pub mod seeders;
26pub mod exports;
27
28// The module's extension (hand-written; ADR-0031).
29#[path = "lib.ext.rs"]
30mod lib_ext;
31pub use lib_ext::*;
32/// This crate's module and builder under fixed names, for the extension's `impl` blocks.
33#[allow(dead_code)]
34pub(crate) type ThisModule = AccountingModule;
35#[allow(dead_code)]
36pub(crate) type ThisModuleBuilder = AccountingModuleBuilder;
37
38// Re-exports for convenience - Domain entities
39pub use domain::entity::*;
40
41// Re-exports - Infrastructure
42pub use infrastructure::persistence::*;
43
44// Re-exports - Application services
45pub use application::service::AccountService;
46pub use application::service::AccountingPostService;
47pub use application::service::CostCenterService;
48pub use application::service::EmvQrConfigService;
49pub use application::service::BankCheckSequenceService;
50pub use application::service::PrintedCheckService;
51pub use application::service::TaxTagRepairRunService;
52pub use application::service::FinancialStatementService;
53pub use application::service::FiscalPeriodService;
54pub use application::service::JournalService;
55pub use application::service::JournalLineService;
56pub use application::service::LedgerService;
57pub use application::service::ReconciliationService;
58pub use application::service::ReconciliationItemService;
59pub use application::service::FullReconcileService;
60pub use application::service::PartialReconcileService;
61
62// Re-exports - Workflows
63pub use application::workflows::*;
64
65use std::sync::Arc;
66use axum::Router;
67use sqlx::PgPool;
68
69/// Accounting module configuration
70///
71/// Use the builder pattern to configure and register this module:
72///
73/// ```text
74/// let accounting = AccountingModule::builder()
75///     .with_database(pool.clone())
76///     .build()?;
77///
78/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
79/// let router = accounting.all_crud_routes();
80/// ```
81pub struct AccountingModule {
82    pub(crate) account_service: Arc<AccountService>,
83    pub(crate) accounting_post_service: Arc<AccountingPostService>,
84    pub(crate) cost_center_service: Arc<CostCenterService>,
85    pub(crate) emv_qr_config_service: Arc<EmvQrConfigService>,
86    pub(crate) bank_check_sequence_service: Arc<BankCheckSequenceService>,
87    pub(crate) printed_check_service: Arc<PrintedCheckService>,
88    pub(crate) tax_tag_repair_run_service: Arc<TaxTagRepairRunService>,
89    pub(crate) financial_statement_service: Arc<FinancialStatementService>,
90    pub(crate) fiscal_period_service: Arc<FiscalPeriodService>,
91    pub(crate) journal_service: Arc<JournalService>,
92    pub(crate) journal_line_service: Arc<JournalLineService>,
93    pub(crate) ledger_service: Arc<LedgerService>,
94    pub(crate) reconciliation_service: Arc<ReconciliationService>,
95    pub(crate) reconciliation_item_service: Arc<ReconciliationItemService>,
96    pub(crate) full_reconcile_service: Arc<FullReconcileService>,
97    pub(crate) partial_reconcile_service: Arc<PartialReconcileService>,
98    /// The module's extension state (`lib.ext.rs`); its fields read through `Deref`.
99    pub(crate) ext: ModuleExt,
100}
101
102impl std::ops::Deref for AccountingModule {
103    type Target = ModuleExt;
104    fn deref(&self) -> &Self::Target {
105        &self.ext
106    }
107}
108
109impl std::ops::DerefMut for AccountingModule {
110    fn deref_mut(&mut self) -> &mut Self::Target {
111        &mut self.ext
112    }
113}
114
115/// What the extension's `build` hook receives from the generated build (ADR-0031).
116#[allow(dead_code)]
117pub(crate) struct ModuleParts<'a> {
118    pub(crate) db_pool: &'a PgPool,
119    pub(crate) account_service: &'a Arc<AccountService>,
120    pub(crate) account_repository: &'a Arc<AccountRepository>,
121    pub(crate) accounting_post_service: &'a Arc<AccountingPostService>,
122    pub(crate) accounting_post_repository: &'a Arc<AccountingPostRepository>,
123    pub(crate) cost_center_service: &'a Arc<CostCenterService>,
124    pub(crate) cost_center_repository: &'a Arc<CostCenterRepository>,
125    pub(crate) emv_qr_config_service: &'a Arc<EmvQrConfigService>,
126    pub(crate) emv_qr_config_repository: &'a Arc<EmvQrConfigRepository>,
127    pub(crate) bank_check_sequence_service: &'a Arc<BankCheckSequenceService>,
128    pub(crate) bank_check_sequence_repository: &'a Arc<BankCheckSequenceRepository>,
129    pub(crate) printed_check_service: &'a Arc<PrintedCheckService>,
130    pub(crate) printed_check_repository: &'a Arc<PrintedCheckRepository>,
131    pub(crate) tax_tag_repair_run_service: &'a Arc<TaxTagRepairRunService>,
132    pub(crate) tax_tag_repair_run_repository: &'a Arc<TaxTagRepairRunRepository>,
133    pub(crate) financial_statement_service: &'a Arc<FinancialStatementService>,
134    pub(crate) financial_statement_repository: &'a Arc<FinancialStatementRepository>,
135    pub(crate) fiscal_period_service: &'a Arc<FiscalPeriodService>,
136    pub(crate) fiscal_period_repository: &'a Arc<FiscalPeriodRepository>,
137    pub(crate) journal_service: &'a Arc<JournalService>,
138    pub(crate) journal_repository: &'a Arc<JournalRepository>,
139    pub(crate) journal_line_service: &'a Arc<JournalLineService>,
140    pub(crate) journal_line_repository: &'a Arc<JournalLineRepository>,
141    pub(crate) ledger_service: &'a Arc<LedgerService>,
142    pub(crate) ledger_repository: &'a Arc<LedgerRepository>,
143    pub(crate) reconciliation_service: &'a Arc<ReconciliationService>,
144    pub(crate) reconciliation_repository: &'a Arc<ReconciliationRepository>,
145    pub(crate) reconciliation_item_service: &'a Arc<ReconciliationItemService>,
146    pub(crate) reconciliation_item_repository: &'a Arc<ReconciliationItemRepository>,
147    pub(crate) full_reconcile_service: &'a Arc<FullReconcileService>,
148    pub(crate) full_reconcile_repository: &'a Arc<FullReconcileRepository>,
149    pub(crate) partial_reconcile_service: &'a Arc<PartialReconcileService>,
150    pub(crate) partial_reconcile_repository: &'a Arc<PartialReconcileRepository>,
151}
152
153impl AccountingModule {
154    /// Create a new module builder
155    pub fn builder() -> AccountingModuleBuilder {
156        AccountingModuleBuilder::new()
157    }
158
159    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
160    /// validation — the fully **unguarded** surface. A well-formed request can
161    /// create invalid rows or soft-delete a referenced master out from under its
162    /// dependents. Prefer a guarded composition (read + validated writes) for any
163    /// real deployment; use this only in trusted/admin/seeding contexts.
164    pub fn all_crud_routes(&self) -> Router {
165        use presentation::http::{
166            create_account_routes,
167            create_accounting_post_routes,
168            create_cost_center_routes,
169            create_emv_qr_config_routes,
170            create_bank_check_sequence_routes,
171            create_printed_check_routes,
172            create_tax_tag_repair_run_routes,
173            create_financial_statement_routes,
174            create_fiscal_period_read_routes,
175            create_journal_routes,
176            create_journal_line_routes,
177            create_ledger_routes,
178            create_reconciliation_routes,
179            create_reconciliation_item_routes,
180            create_full_reconcile_routes,
181            create_partial_reconcile_routes,
182        };
183
184        Router::new()
185            .merge(create_account_routes(self.account_service.clone()))
186            .merge(create_accounting_post_routes(self.accounting_post_service.clone()))
187            .merge(create_cost_center_routes(self.cost_center_service.clone()))
188            .merge(create_emv_qr_config_routes(self.emv_qr_config_service.clone()))
189            .merge(create_bank_check_sequence_routes(self.bank_check_sequence_service.clone()))
190            .merge(create_printed_check_routes(self.printed_check_service.clone()))
191            .merge(create_tax_tag_repair_run_routes(self.tax_tag_repair_run_service.clone()))
192            .merge(create_financial_statement_routes(self.financial_statement_service.clone()))
193            // FiscalPeriod: hand_set lifecycle — the state field moves only through the
194            // module's validated verbs; generic writes cannot reach it, so only the
195            // read surface mounts here.
196            .merge(create_fiscal_period_read_routes(self.fiscal_period_service.clone()))
197            .merge(create_journal_routes(self.journal_service.clone()))
198            .merge(create_journal_line_routes(self.journal_line_service.clone()))
199            .merge(create_ledger_routes(self.ledger_service.clone()))
200            .merge(create_reconciliation_routes(self.reconciliation_service.clone()))
201            .merge(create_reconciliation_item_routes(self.reconciliation_item_service.clone()))
202            .merge(create_full_reconcile_routes(self.full_reconcile_service.clone()))
203            .merge(create_partial_reconcile_routes(self.partial_reconcile_service.clone()))
204    }
205
206    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
207    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
208    /// mount exposes unguarded writes. Compose a guarded router (read + validated
209    /// writes) for production, or call `all_crud_routes()` to opt into the full
210    /// unguarded surface explicitly.
211    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
212    pub fn routes(&self) -> Router {
213        self.all_crud_routes()
214    }
215
216    /// Read-only routes for every entity (GET endpoints only) — the safe base.
217    ///
218    /// Generic mutation can't reach here, so this surface cannot bypass a
219    /// validated write service's invariants. Use this as the production base and
220    /// merge validated write routes (or a write service's HTTP layer) onto it.
221    pub fn readonly_routes(&self) -> Router {
222        use presentation::http::{
223            create_account_read_routes,
224            create_accounting_post_read_routes,
225            create_cost_center_read_routes,
226            create_emv_qr_config_read_routes,
227            create_bank_check_sequence_read_routes,
228            create_printed_check_read_routes,
229            create_tax_tag_repair_run_read_routes,
230            create_financial_statement_read_routes,
231            create_fiscal_period_read_routes,
232            create_journal_read_routes,
233            create_journal_line_read_routes,
234            create_ledger_read_routes,
235            create_reconciliation_read_routes,
236            create_reconciliation_item_read_routes,
237            create_full_reconcile_read_routes,
238            create_partial_reconcile_read_routes,
239        };
240
241        Router::new()
242            .merge(create_account_read_routes(self.account_service.clone()))
243            .merge(create_accounting_post_read_routes(self.accounting_post_service.clone()))
244            .merge(create_cost_center_read_routes(self.cost_center_service.clone()))
245            .merge(create_emv_qr_config_read_routes(self.emv_qr_config_service.clone()))
246            .merge(create_bank_check_sequence_read_routes(self.bank_check_sequence_service.clone()))
247            .merge(create_printed_check_read_routes(self.printed_check_service.clone()))
248            .merge(create_tax_tag_repair_run_read_routes(self.tax_tag_repair_run_service.clone()))
249            .merge(create_financial_statement_read_routes(self.financial_statement_service.clone()))
250            .merge(create_fiscal_period_read_routes(self.fiscal_period_service.clone()))
251            .merge(create_journal_read_routes(self.journal_service.clone()))
252            .merge(create_journal_line_read_routes(self.journal_line_service.clone()))
253            .merge(create_ledger_read_routes(self.ledger_service.clone()))
254            .merge(create_reconciliation_read_routes(self.reconciliation_service.clone()))
255            .merge(create_reconciliation_item_read_routes(self.reconciliation_item_service.clone()))
256            .merge(create_full_reconcile_read_routes(self.full_reconcile_service.clone()))
257            .merge(create_partial_reconcile_read_routes(self.partial_reconcile_service.clone()))
258    }
259
260}
261
262/// Builder for AccountingModule
263pub struct AccountingModuleBuilder {
264    db_pool: Option<PgPool>,
265    /// The builder's extension state (`lib.ext.rs`); its fields read through `Deref`.
266    ext: ModuleBuilderExt,
267}
268
269impl std::ops::Deref for AccountingModuleBuilder {
270    type Target = ModuleBuilderExt;
271    fn deref(&self) -> &Self::Target {
272        &self.ext
273    }
274}
275
276impl std::ops::DerefMut for AccountingModuleBuilder {
277    fn deref_mut(&mut self) -> &mut Self::Target {
278        &mut self.ext
279    }
280}
281
282impl AccountingModuleBuilder {
283    /// Create a new builder
284    pub fn new() -> Self {
285        Self {
286            db_pool: None,
287            ext: Default::default(),
288        }
289    }
290
291    /// Set the database connection pool
292    pub fn with_database(mut self, pool: PgPool) -> Self {
293        self.db_pool = Some(pool);
294        self
295    }
296
297
298    /// Build the module with configured dependencies
299    pub fn build(self) -> anyhow::Result<AccountingModule> {
300        let db_pool = self.db_pool
301            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
302
303        // Account service
304        let account_repository = Arc::new(AccountRepository::new(db_pool.clone()));
305        let account_service = Arc::new(AccountService::with_repository(account_repository.clone()).with_guard(Arc::new(crate::application::service::AccountRowRules)));
306
307        // AccountingPost service
308        let accounting_post_repository = Arc::new(AccountingPostRepository::new(db_pool.clone()));
309        let accounting_post_service = Arc::new(AccountingPostService::with_repository(accounting_post_repository.clone()).with_guard(Arc::new(crate::application::service::AccountingPostRowRules)));
310
311        // CostCenter service
312        let cost_center_repository = Arc::new(CostCenterRepository::new(db_pool.clone()));
313        let cost_center_service = Arc::new(CostCenterService::with_repository(cost_center_repository.clone()).with_guard(Arc::new(crate::application::service::CostCenterRowRules)));
314
315        // EmvQrConfig service
316        let emv_qr_config_repository = Arc::new(EmvQrConfigRepository::new(db_pool.clone()));
317        let emv_qr_config_service = Arc::new(EmvQrConfigService::with_repository(emv_qr_config_repository.clone()).with_guard(Arc::new(crate::application::service::EmvQrConfigRowRules)));
318
319        // BankCheckSequence service
320        let bank_check_sequence_repository = Arc::new(BankCheckSequenceRepository::new(db_pool.clone()));
321        let bank_check_sequence_service = Arc::new(BankCheckSequenceService::with_repository(bank_check_sequence_repository.clone()).with_guard(Arc::new(crate::application::service::BankCheckSequenceRowRules)));
322
323        // PrintedCheck service
324        let printed_check_repository = Arc::new(PrintedCheckRepository::new(db_pool.clone()));
325        let printed_check_service = Arc::new(PrintedCheckService::with_repository(printed_check_repository.clone()).with_guard(Arc::new(crate::application::service::PrintedCheckRowRules)));
326
327        // TaxTagRepairRun service
328        let tax_tag_repair_run_repository = Arc::new(TaxTagRepairRunRepository::new(db_pool.clone()));
329        let tax_tag_repair_run_service = Arc::new(TaxTagRepairRunService::with_repository(tax_tag_repair_run_repository.clone()).with_guard(Arc::new(crate::application::service::TaxTagRepairRunRowRules)));
330
331        // FinancialStatement service
332        let financial_statement_repository = Arc::new(FinancialStatementRepository::new(db_pool.clone()));
333        let financial_statement_service = Arc::new(FinancialStatementService::with_repository(financial_statement_repository.clone()).with_guard(Arc::new(crate::application::service::FinancialStatementRowRules)));
334
335        // FiscalPeriod service
336        let fiscal_period_repository = Arc::new(FiscalPeriodRepository::new(db_pool.clone()));
337        let fiscal_period_service = Arc::new(FiscalPeriodService::with_repository(fiscal_period_repository.clone()).with_guard(Arc::new(crate::application::service::FiscalPeriodRowRules)));
338
339        // Journal service
340        let journal_repository = Arc::new(JournalRepository::new(db_pool.clone()));
341        let journal_service = Arc::new(JournalService::with_repository(journal_repository.clone()).with_guard(Arc::new(crate::application::service::JournalRowRules)));
342
343        // JournalLine service
344        let journal_line_repository = Arc::new(JournalLineRepository::new(db_pool.clone()));
345        let journal_line_service = Arc::new(JournalLineService::with_repository(journal_line_repository.clone()).with_guard(Arc::new(crate::application::service::JournalLineRowRules)));
346
347        // Ledger service
348        let ledger_repository = Arc::new(LedgerRepository::new(db_pool.clone()));
349        let ledger_service = Arc::new(LedgerService::with_repository(ledger_repository.clone()).with_guard(Arc::new(crate::application::service::LedgerRowRules)));
350
351        // Reconciliation service
352        let reconciliation_repository = Arc::new(ReconciliationRepository::new(db_pool.clone()));
353        let reconciliation_service = Arc::new(ReconciliationService::with_repository(reconciliation_repository.clone()).with_guard(Arc::new(crate::application::service::ReconciliationRowRules)));
354
355        // ReconciliationItem service
356        let reconciliation_item_repository = Arc::new(ReconciliationItemRepository::new(db_pool.clone()));
357        let reconciliation_item_service = Arc::new(ReconciliationItemService::with_repository(reconciliation_item_repository.clone()).with_guard(Arc::new(crate::application::service::ReconciliationItemRowRules)));
358
359        // FullReconcile service
360        let full_reconcile_repository = Arc::new(FullReconcileRepository::new(db_pool.clone()));
361        let full_reconcile_service = Arc::new(FullReconcileService::with_repository(full_reconcile_repository.clone()));
362
363        // PartialReconcile service
364        let partial_reconcile_repository = Arc::new(PartialReconcileRepository::new(db_pool.clone()));
365        let partial_reconcile_service = Arc::new(PartialReconcileService::with_repository(partial_reconcile_repository.clone()).with_guard(Arc::new(crate::application::service::PartialReconcileRowRules)));
366
367
368        // The extension builds its own state from what the generated build made.
369        let ext = self.ext.build(&ModuleParts {
370            db_pool: &db_pool,
371            account_service: &account_service,
372            account_repository: &account_repository,
373            accounting_post_service: &accounting_post_service,
374            accounting_post_repository: &accounting_post_repository,
375            cost_center_service: &cost_center_service,
376            cost_center_repository: &cost_center_repository,
377            emv_qr_config_service: &emv_qr_config_service,
378            emv_qr_config_repository: &emv_qr_config_repository,
379            bank_check_sequence_service: &bank_check_sequence_service,
380            bank_check_sequence_repository: &bank_check_sequence_repository,
381            printed_check_service: &printed_check_service,
382            printed_check_repository: &printed_check_repository,
383            tax_tag_repair_run_service: &tax_tag_repair_run_service,
384            tax_tag_repair_run_repository: &tax_tag_repair_run_repository,
385            financial_statement_service: &financial_statement_service,
386            financial_statement_repository: &financial_statement_repository,
387            fiscal_period_service: &fiscal_period_service,
388            fiscal_period_repository: &fiscal_period_repository,
389            journal_service: &journal_service,
390            journal_repository: &journal_repository,
391            journal_line_service: &journal_line_service,
392            journal_line_repository: &journal_line_repository,
393            ledger_service: &ledger_service,
394            ledger_repository: &ledger_repository,
395            reconciliation_service: &reconciliation_service,
396            reconciliation_repository: &reconciliation_repository,
397            reconciliation_item_service: &reconciliation_item_service,
398            reconciliation_item_repository: &reconciliation_item_repository,
399            full_reconcile_service: &full_reconcile_service,
400            full_reconcile_repository: &full_reconcile_repository,
401            partial_reconcile_service: &partial_reconcile_service,
402            partial_reconcile_repository: &partial_reconcile_repository,
403        })?;
404
405        Ok(AccountingModule {
406            account_service,
407            accounting_post_service,
408            cost_center_service,
409            emv_qr_config_service,
410            bank_check_sequence_service,
411            printed_check_service,
412            tax_tag_repair_run_service,
413            financial_statement_service,
414            fiscal_period_service,
415            journal_service,
416            journal_line_service,
417            ledger_service,
418            reconciliation_service,
419            reconciliation_item_service,
420            full_reconcile_service,
421            partial_reconcile_service,
422            ext,
423        })
424    }
425}
426
427impl Default for AccountingModuleBuilder {
428    fn default() -> Self {
429        Self::new()
430    }
431}