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// <<< CUSTOM MODULES
28// END CUSTOM
29
30// Re-exports for convenience - Domain entities
31pub use domain::entity::*;
32
33// Re-exports - Infrastructure
34pub use infrastructure::persistence::*;
35
36// Re-exports - Application services
37pub use application::service::AccountService;
38pub use application::service::AccountingPostService;
39pub use application::service::CostCenterService;
40pub use application::service::EmvQrConfigService;
41pub use application::service::BankCheckSequenceService;
42pub use application::service::PrintedCheckService;
43pub use application::service::TaxTagRepairRunService;
44pub use application::service::FinancialStatementService;
45pub use application::service::FiscalPeriodService;
46pub use application::service::JournalService;
47pub use application::service::JournalLineService;
48pub use application::service::LedgerService;
49pub use application::service::ReconciliationService;
50pub use application::service::ReconciliationItemService;
51pub use application::service::FullReconcileService;
52pub use application::service::PartialReconcileService;
53
54// Re-exports - Validation
55pub use application::validator::{ValidationError, ValidationResult};
56
57// Re-exports - Workflows
58pub use application::workflows::*;
59
60use std::sync::Arc;
61use axum::Router;
62use sqlx::PgPool;
63
64/// Accounting module configuration
65///
66/// Use the builder pattern to configure and register this module:
67///
68/// ```text
69/// let accounting = AccountingModule::builder()
70///     .with_database(pool.clone())
71///     .build()?;
72///
73/// // Unguarded full CRUD (trusted/admin); compose a guarded router for production.
74/// let router = accounting.all_crud_routes();
75/// ```
76pub struct AccountingModule {
77    pub(crate) account_service: Arc<AccountService>,
78    pub(crate) accounting_post_service: Arc<AccountingPostService>,
79    pub(crate) cost_center_service: Arc<CostCenterService>,
80    pub(crate) emv_qr_config_service: Arc<EmvQrConfigService>,
81    pub(crate) bank_check_sequence_service: Arc<BankCheckSequenceService>,
82    pub(crate) printed_check_service: Arc<PrintedCheckService>,
83    pub(crate) tax_tag_repair_run_service: Arc<TaxTagRepairRunService>,
84    pub(crate) financial_statement_service: Arc<FinancialStatementService>,
85    pub(crate) fiscal_period_service: Arc<FiscalPeriodService>,
86    pub(crate) journal_service: Arc<JournalService>,
87    pub(crate) journal_line_service: Arc<JournalLineService>,
88    pub(crate) ledger_service: Arc<LedgerService>,
89    pub(crate) reconciliation_service: Arc<ReconciliationService>,
90    pub(crate) reconciliation_item_service: Arc<ReconciliationItemService>,
91    pub(crate) full_reconcile_service: Arc<FullReconcileService>,
92    pub(crate) partial_reconcile_service: Arc<PartialReconcileService>,
93    // <<< CUSTOM FIELDS
94    pub(crate) db_pool: PgPool,
95    pub(crate) reconcile_write_service:
96        Arc<crate::application::service::reconcile_write_service::ReconcileWriteService>,
97    /// The check printing surface: per-bank-journal check-number sequences and
98    /// the printed-check registry.
99    pub(crate) check_printing_service:
100        Arc<crate::application::service::check_printing_service::CheckPrintingService>,
101    /// The EMV(QRCPS)/QRIS display surface: merchant QR configuration and the
102    /// invoice payload render.
103    pub(crate) emv_qr_service:
104        Arc<crate::application::service::emv_qr_service::EmvQrService>,
105    /// The tax-tag legal-change repair verb and its audit ledger read.
106    pub(crate) tax_tag_repair_service:
107        Arc<crate::application::service::tax_tag_repair_service::TaxTagRepairService>,
108    /// Host-implemented cash-basis tax deferral lookup, kept so post-build
109    /// service variants (e.g. the exchange-account one) keep the flip wired.
110    pub(crate) deferred_tax: Option<Arc<dyn crate::domain::repositories::DeferredTaxLookup>>,
111    /// Host-implemented budget control, kept so every posting path the host
112    /// builds from this module (the HTTP posting verb, the journal workflow,
113    /// the period close) can arm the consult from one registration.
114    pub(crate) budget_control: Option<Arc<dyn crate::domain::repositories::BudgetControlPort>>,
115    /// Chart install engine over the datasets registered via `with_chart_dataset`.
116    pub(crate) chart_install_service:
117        Arc<crate::application::service::chart_install_service::ChartInstallService>,
118    /// On-the-fly financial reports (TB tree, BS, P&L, GL, partner ledger, aged AR/AP).
119    pub(crate) reporting_service:
120        Arc<crate::application::service::reporting_service::ReportingService>,
121    // END CUSTOM
122}
123
124impl AccountingModule {
125    /// Create a new module builder
126    pub fn builder() -> AccountingModuleBuilder {
127        AccountingModuleBuilder::new()
128    }
129
130    /// Mount ALL generated CRUD endpoints (12 per entity) with NO domain
131    /// validation — the fully **unguarded** surface. A well-formed request can
132    /// create invalid rows or soft-delete a referenced master out from under its
133    /// dependents. Prefer a guarded composition (read + validated writes) for any
134    /// real deployment; use this only in trusted/admin/seeding contexts.
135    pub fn all_crud_routes(&self) -> Router {
136        use presentation::http::{
137            create_account_routes,
138            create_accounting_post_routes,
139            create_cost_center_routes,
140            create_emv_qr_config_routes,
141            create_bank_check_sequence_routes,
142            create_printed_check_routes,
143            create_tax_tag_repair_run_routes,
144            create_financial_statement_routes,
145            create_fiscal_period_read_routes,
146            create_journal_routes,
147            create_journal_line_routes,
148            create_ledger_routes,
149            create_reconciliation_routes,
150            create_reconciliation_item_routes,
151            create_full_reconcile_routes,
152            create_partial_reconcile_routes,
153        };
154
155        Router::new()
156            .merge(create_account_routes(self.account_service.clone()))
157            .merge(create_accounting_post_routes(self.accounting_post_service.clone()))
158            .merge(create_cost_center_routes(self.cost_center_service.clone()))
159            .merge(create_emv_qr_config_routes(self.emv_qr_config_service.clone()))
160            .merge(create_bank_check_sequence_routes(self.bank_check_sequence_service.clone()))
161            .merge(create_printed_check_routes(self.printed_check_service.clone()))
162            .merge(create_tax_tag_repair_run_routes(self.tax_tag_repair_run_service.clone()))
163            .merge(create_financial_statement_routes(self.financial_statement_service.clone()))
164            // FiscalPeriod: hand_set lifecycle — the state field moves only through the
165            // module's validated verbs; generic writes cannot reach it, so only the
166            // read surface mounts here.
167            .merge(create_fiscal_period_read_routes(self.fiscal_period_service.clone()))
168            .merge(create_journal_routes(self.journal_service.clone()))
169            .merge(create_journal_line_routes(self.journal_line_service.clone()))
170            .merge(create_ledger_routes(self.ledger_service.clone()))
171            .merge(create_reconciliation_routes(self.reconciliation_service.clone()))
172            .merge(create_reconciliation_item_routes(self.reconciliation_item_service.clone()))
173            .merge(create_full_reconcile_routes(self.full_reconcile_service.clone()))
174            .merge(create_partial_reconcile_routes(self.partial_reconcile_service.clone()))
175    }
176
177    /// Deprecated alias for [`Self::all_crud_routes`]. `routes()` reads like
178    /// "the routes" but mounts UNVALIDATED generic CRUD on every entity — a naive
179    /// mount exposes unguarded writes. Compose a guarded router (read + validated
180    /// writes) for production, or call `all_crud_routes()` to opt into the full
181    /// unguarded surface explicitly.
182    #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
183    pub fn routes(&self) -> Router {
184        self.all_crud_routes()
185    }
186
187    /// Read-only routes for every entity (GET endpoints only) — the safe base.
188    ///
189    /// Generic mutation can't reach here, so this surface cannot bypass a
190    /// validated write service's invariants. Use this as the production base and
191    /// merge validated write routes (or a write service's HTTP layer) onto it.
192    pub fn readonly_routes(&self) -> Router {
193        use presentation::http::{
194            create_account_read_routes,
195            create_accounting_post_read_routes,
196            create_cost_center_read_routes,
197            create_emv_qr_config_read_routes,
198            create_bank_check_sequence_read_routes,
199            create_printed_check_read_routes,
200            create_tax_tag_repair_run_read_routes,
201            create_financial_statement_read_routes,
202            create_fiscal_period_read_routes,
203            create_journal_read_routes,
204            create_journal_line_read_routes,
205            create_ledger_read_routes,
206            create_reconciliation_read_routes,
207            create_reconciliation_item_read_routes,
208            create_full_reconcile_read_routes,
209            create_partial_reconcile_read_routes,
210        };
211
212        Router::new()
213            .merge(create_account_read_routes(self.account_service.clone()))
214            .merge(create_accounting_post_read_routes(self.accounting_post_service.clone()))
215            .merge(create_cost_center_read_routes(self.cost_center_service.clone()))
216            .merge(create_emv_qr_config_read_routes(self.emv_qr_config_service.clone()))
217            .merge(create_bank_check_sequence_read_routes(self.bank_check_sequence_service.clone()))
218            .merge(create_printed_check_read_routes(self.printed_check_service.clone()))
219            .merge(create_tax_tag_repair_run_read_routes(self.tax_tag_repair_run_service.clone()))
220            .merge(create_financial_statement_read_routes(self.financial_statement_service.clone()))
221            .merge(create_fiscal_period_read_routes(self.fiscal_period_service.clone()))
222            .merge(create_journal_read_routes(self.journal_service.clone()))
223            .merge(create_journal_line_read_routes(self.journal_line_service.clone()))
224            .merge(create_ledger_read_routes(self.ledger_service.clone()))
225            .merge(create_reconciliation_read_routes(self.reconciliation_service.clone()))
226            .merge(create_reconciliation_item_read_routes(self.reconciliation_item_service.clone()))
227            .merge(create_full_reconcile_read_routes(self.full_reconcile_service.clone()))
228            .merge(create_partial_reconcile_read_routes(self.partial_reconcile_service.clone()))
229    }
230
231    // <<< CUSTOM METHODS
232    /// The registered budget-control port, if any — the single registration a
233    /// host threads into every `PostingService` it builds from this module
234    /// (`.with_budget_control_if_set(m.budget_control())`), so the HTTP
235    /// posting verb, the journal workflow, and the period close all consult
236    /// the same control.
237    pub fn budget_control(
238        &self,
239    ) -> Option<Arc<dyn crate::domain::repositories::BudgetControlPort>> {
240        self.budget_control.clone()
241    }
242
243    /// The on-the-fly financial reports (Trial Balance tree, Balance Sheet, Income
244    /// Statement, General Ledger, Partner Ledger, Aged AR/AP). Read-only; scoped reads.
245    pub fn reporting_service(
246        &self,
247    ) -> std::sync::Arc<crate::application::service::reporting_service::ReportingService> {
248        self.reporting_service.clone()
249    }
250
251    /// The reconciliation write service — the ONLY sanctioned writer of the
252    /// reconciliation graph (guards + CLAMP + side-effecting unlink). The graph tables
253    /// carry no CRUD surface anywhere; `guarded_routes` mounts its verb routes.
254    pub fn reconcile_write_service(
255        &self,
256    ) -> std::sync::Arc<crate::application::service::reconcile_write_service::ReconcileWriteService>
257    {
258        self.reconcile_write_service.clone()
259    }
260
261    /// Build a reconcile write service with the FX (exchange-difference) account
262    /// configured. Without one, any rate divergence that demands an exchange move fails
263    /// closed (`exchange_account_unconfigured`) — normal single-currency posts never
264    /// generate one, so the default service is complete for them.
265    pub fn reconcile_write_service_with_exchange_account(
266        &self,
267        exchange_account_id: uuid::Uuid,
268    ) -> std::sync::Arc<crate::application::service::reconcile_write_service::ReconcileWriteService>
269    {
270        std::sync::Arc::new(
271            crate::application::service::reconcile_write_service::ReconcileWriteService::new(
272                std::sync::Arc::new(
273                    crate::infrastructure::persistence::reconcile_graph_repository::SqlxReconcileGraphRepository::new(),
274                ),
275                std::sync::Arc::new(
276                    crate::infrastructure::persistence::posting_repository::SqlxPostingRepository::new(
277                        self.db_pool.clone(),
278                    ),
279                ),
280                self.db_pool.clone(),
281                Some(exchange_account_id),
282            )
283            .with_deferred_tax_if_set(self.deferred_tax.clone()),
284        )
285    }
286
287    /// The chart install engine — validates, gates, and writes a registered chart
288    /// dataset into the accounts, idempotently. The install VERB itself is
289    /// host-mounted (it orchestrates beyond this module); this handle is the engine
290    /// the host verb drives.
291    pub fn chart_install_service(
292        &self,
293    ) -> std::sync::Arc<crate::application::service::chart_install_service::ChartInstallService>
294    {
295        self.chart_install_service.clone()
296    }
297
298    /// The check printing surface — sequence registration, atomic number
299    /// allocation, the printed-check registry, and voids. `guarded_routes`
300    /// mounts its verb routes; there is no CRUD path to these tables.
301    pub fn check_printing_service(
302        &self,
303    ) -> std::sync::Arc<crate::application::service::check_printing_service::CheckPrintingService>
304    {
305        self.check_printing_service.clone()
306    }
307
308    /// The EMV(QRCPS)/QRIS display surface — merchant QR configuration and the
309    /// invoice payload render (payloads are built on demand, never stored).
310    pub fn emv_qr_service(
311        &self,
312    ) -> std::sync::Arc<crate::application::service::emv_qr_service::EmvQrService> {
313        self.emv_qr_service.clone()
314    }
315
316    /// The tax-tag legal-change repair verb (reason mandatory, locked periods
317    /// refused, closed periods overridden explicitly, every run audit-stamped)
318    /// plus its audit-ledger read.
319    pub fn tax_tag_repair_service(
320        &self,
321    ) -> std::sync::Arc<crate::application::service::tax_tag_repair_service::TaxTagRepairService>
322    {
323        self.tax_tag_repair_service.clone()
324    }
325    // END CUSTOM
326}
327
328/// Builder for AccountingModule
329pub struct AccountingModuleBuilder {
330    db_pool: Option<PgPool>,
331    // <<< CUSTOM BUILDER FIELDS
332    deferred_tax: Option<Arc<dyn crate::domain::repositories::DeferredTaxLookup>>,
333    budget_control: Option<Arc<dyn crate::domain::repositories::BudgetControlPort>>,
334    chart_datasets: Vec<Arc<crate::domain::chart_dataset::ChartDataset>>,
335    // END CUSTOM
336}
337
338impl AccountingModuleBuilder {
339    /// Create a new builder
340    pub fn new() -> Self {
341        Self {
342            db_pool: None,
343            // <<< CUSTOM BUILDER DEFAULTS
344            deferred_tax: None,
345            budget_control: None,
346            chart_datasets: Vec::new(),
347            // END CUSTOM
348        }
349    }
350
351    /// Set the database connection pool
352    pub fn with_database(mut self, pool: PgPool) -> Self {
353        self.db_pool = Some(pool);
354        self
355    }
356
357    // <<< CUSTOM - custom builder methods
358    /// Register a chart-of-accounts dataset installable through the chart install
359    /// engine. Datasets are data (commonly shipped by an l10n module); registering
360    /// one makes it listable via `GET /accounting/charts` and installable by the
361    /// host-mounted install verb.
362    pub fn with_chart_dataset(
363        mut self,
364        dataset: Arc<crate::domain::chart_dataset::ChartDataset>,
365    ) -> Self {
366        self.chart_datasets.push(dataset);
367        self
368    }
369
370    /// Wire the host's cash-basis tax deferral lookup: partial reconciliations
371    /// landing on receivable/payable lines flip deferred (on_payment) tax
372    /// pro-rata from the transition account onto the real tax account. Hosts
373    /// without a tax module leave it unset — no flips, everything else works.
374    pub fn with_deferred_tax(
375        mut self,
376        port: Arc<dyn crate::domain::repositories::DeferredTaxLookup>,
377    ) -> Self {
378        self.deferred_tax = Some(port);
379        self
380    }
381
382    /// Wire the host's budget control: postings through the GL-posting
383    /// chokepoint are checked against confirmed budget positions (account x
384    /// cost center x fiscal period) after the pure double-entry rules pass.
385    /// Warn-enforcement breaches log and proceed; block-enforcement breaches
386    /// refuse the posting. Hosts without a budget module leave it unset — no
387    /// check, everything else works (fail-open).
388    pub fn with_budget_control(
389        mut self,
390        port: Arc<dyn crate::domain::repositories::BudgetControlPort>,
391    ) -> Self {
392        self.budget_control = Some(port);
393        self
394    }
395    // END CUSTOM
396
397    /// Build the module with configured dependencies
398    pub fn build(self) -> anyhow::Result<AccountingModule> {
399        let db_pool = self.db_pool
400            .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
401
402        // Account service
403        let account_repository = Arc::new(AccountRepository::new(db_pool.clone()));
404        let account_service = Arc::new(AccountService::with_repository(account_repository.clone()));
405
406        // AccountingPost service
407        let accounting_post_repository = Arc::new(AccountingPostRepository::new(db_pool.clone()));
408        let accounting_post_service = Arc::new(AccountingPostService::with_repository(accounting_post_repository.clone()));
409
410        // CostCenter service
411        let cost_center_repository = Arc::new(CostCenterRepository::new(db_pool.clone()));
412        let cost_center_service = Arc::new(CostCenterService::with_repository(cost_center_repository.clone()));
413
414        // EmvQrConfig service
415        let emv_qr_config_repository = Arc::new(EmvQrConfigRepository::new(db_pool.clone()));
416        let emv_qr_config_service = Arc::new(EmvQrConfigService::with_repository(emv_qr_config_repository.clone()));
417
418        // BankCheckSequence service
419        let bank_check_sequence_repository = Arc::new(BankCheckSequenceRepository::new(db_pool.clone()));
420        let bank_check_sequence_service = Arc::new(BankCheckSequenceService::with_repository(bank_check_sequence_repository.clone()));
421
422        // PrintedCheck service
423        let printed_check_repository = Arc::new(PrintedCheckRepository::new(db_pool.clone()));
424        let printed_check_service = Arc::new(PrintedCheckService::with_repository(printed_check_repository.clone()));
425
426        // TaxTagRepairRun service
427        let tax_tag_repair_run_repository = Arc::new(TaxTagRepairRunRepository::new(db_pool.clone()));
428        let tax_tag_repair_run_service = Arc::new(TaxTagRepairRunService::with_repository(tax_tag_repair_run_repository.clone()));
429
430        // FinancialStatement service
431        let financial_statement_repository = Arc::new(FinancialStatementRepository::new(db_pool.clone()));
432        let financial_statement_service = Arc::new(FinancialStatementService::with_repository(financial_statement_repository.clone()));
433
434        // FiscalPeriod service
435        let fiscal_period_repository = Arc::new(FiscalPeriodRepository::new(db_pool.clone()));
436        let fiscal_period_service = Arc::new(FiscalPeriodService::with_repository(fiscal_period_repository.clone()));
437
438        // Journal service
439        let journal_repository = Arc::new(JournalRepository::new(db_pool.clone()));
440        let journal_service = Arc::new(JournalService::with_repository(journal_repository.clone()));
441
442        // JournalLine service
443        let journal_line_repository = Arc::new(JournalLineRepository::new(db_pool.clone()));
444        let journal_line_service = Arc::new(JournalLineService::with_repository(journal_line_repository.clone()));
445
446        // Ledger service
447        let ledger_repository = Arc::new(LedgerRepository::new(db_pool.clone()));
448        let ledger_service = Arc::new(LedgerService::with_repository(ledger_repository.clone()));
449
450        // Reconciliation service
451        let reconciliation_repository = Arc::new(ReconciliationRepository::new(db_pool.clone()));
452        let reconciliation_service = Arc::new(ReconciliationService::with_repository(reconciliation_repository.clone()));
453
454        // ReconciliationItem service
455        let reconciliation_item_repository = Arc::new(ReconciliationItemRepository::new(db_pool.clone()));
456        let reconciliation_item_service = Arc::new(ReconciliationItemService::with_repository(reconciliation_item_repository.clone()));
457
458        // FullReconcile service
459        let full_reconcile_repository = Arc::new(FullReconcileRepository::new(db_pool.clone()));
460        let full_reconcile_service = Arc::new(FullReconcileService::with_repository(full_reconcile_repository.clone()));
461
462        // PartialReconcile service
463        let partial_reconcile_repository = Arc::new(PartialReconcileRepository::new(db_pool.clone()));
464        let partial_reconcile_service = Arc::new(PartialReconcileService::with_repository(partial_reconcile_repository.clone()));
465
466        // <<< CUSTOM
467        // Reconciliation write service: graph port + posting port (reversals of
468        // generated moves) over the shared pool; no FX account by default (fail-closed).
469        let reconcile_graph_repository = std::sync::Arc::new(
470            crate::infrastructure::persistence::reconcile_graph_repository::SqlxReconcileGraphRepository::new(),
471        );
472        let reconcile_posting_repository = std::sync::Arc::new(
473            crate::infrastructure::persistence::posting_repository::SqlxPostingRepository::new(
474                db_pool.clone(),
475            ),
476        );
477        let reconcile_write_service = std::sync::Arc::new(
478            crate::application::service::reconcile_write_service::ReconcileWriteService::new(
479                reconcile_graph_repository,
480                reconcile_posting_repository,
481                db_pool.clone(),
482                None,
483            )
484            .with_deferred_tax_if_set(self.deferred_tax.clone()),
485        );
486        // Chart install engine: datasets registered by the host drive idempotent
487        // chart installs onto fresh companies (provenance columns identify own rows).
488        let chart_install_service = std::sync::Arc::new(
489            crate::application::service::chart_install_service::ChartInstallService::new(
490                std::sync::Arc::new(
491                    crate::infrastructure::persistence::chart_install_repository::SqlxChartInstallRepository::new(),
492                ),
493                db_pool.clone(),
494                self.chart_datasets,
495            ),
496        );
497        // Financial reports: computed on the fly over the scoped ledger reads.
498        let reporting_service = std::sync::Arc::new(
499            crate::application::service::reporting_service::ReportingService::new(
500                std::sync::Arc::new(
501                    crate::infrastructure::persistence::reporting_repository::SqlxReportingRepository::new(
502                        db_pool.clone(),
503                    ),
504                ),
505            ),
506        );
507        // Check printing: per-bank-journal number sequences + the printed-check
508        // registry, all writes through the guarded verb set.
509        let check_printing_service = std::sync::Arc::new(
510            crate::application::service::check_printing_service::CheckPrintingService::new(
511                db_pool.clone(),
512            ),
513        );
514        // EMV(QRCPS)/QRIS display: merchant QR config + invoice payload render.
515        let emv_qr_service = std::sync::Arc::new(
516            crate::application::service::emv_qr_service::EmvQrService::new(db_pool.clone()),
517        );
518        // Tax-tag legal-change repair verb + its audit ledger read.
519        let tax_tag_repair_service = std::sync::Arc::new(
520            crate::application::service::tax_tag_repair_service::TaxTagRepairService::new(
521                db_pool.clone(),
522            ),
523        );
524        // END CUSTOM
525
526        Ok(AccountingModule {
527            account_service,
528            accounting_post_service,
529            cost_center_service,
530            emv_qr_config_service,
531            bank_check_sequence_service,
532            printed_check_service,
533            tax_tag_repair_run_service,
534            financial_statement_service,
535            fiscal_period_service,
536            journal_service,
537            journal_line_service,
538            ledger_service,
539            reconciliation_service,
540            reconciliation_item_service,
541            full_reconcile_service,
542            partial_reconcile_service,
543            // <<< CUSTOM
544            db_pool,
545            reconcile_write_service,
546            deferred_tax: self.deferred_tax,
547            budget_control: self.budget_control,
548            chart_install_service,
549            reporting_service,
550            check_printing_service,
551            emv_qr_service,
552            tax_tag_repair_service,
553            // END CUSTOM
554        })
555    }
556}
557
558impl Default for AccountingModuleBuilder {
559    fn default() -> Self {
560        Self::new()
561    }
562}