Skip to main content

datasynth_core/models/audit/
service_organization.rs

1//! Service organization and SOC report models per ISA 402.
2//!
3//! ISA 402 addresses the responsibilities of the user auditor when the user entity
4//! uses services provided by a service organization.  When the services form part
5//! of the user entity's information system relevant to financial reporting, the
6//! auditor must obtain an understanding of how that affects the assessment of
7//! risks of material misstatement.
8//!
9//! SOC 1 reports (Service Organization Control 1) describe the controls at a
10//! service organization relevant to user entity's financial reporting.
11
12use chrono::NaiveDate;
13use serde::{Deserialize, Serialize};
14use uuid::Uuid;
15
16/// A service organization used by one or more audited entities.
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ServiceOrganization {
19    /// Unique identifier
20    pub id: String,
21    /// Name of the service organization
22    pub name: String,
23    /// Type of service provided
24    pub service_type: ServiceType,
25    /// Entity codes of user entities served by this organization
26    pub entities_served: Vec<String>,
27}
28
29/// Type of service provided by the service organization.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
31#[serde(rename_all = "snake_case")]
32pub enum ServiceType {
33    /// Payroll processing services
34    #[default]
35    PayrollProcessor,
36    /// Cloud hosting and infrastructure services
37    CloudHosting,
38    /// Payment processing services
39    PaymentProcessor,
40    /// IT managed services
41    ItManagedServices,
42    /// Data centre colocation
43    DataCentre,
44}
45
46/// A SOC 1 report obtained from or about a service organization.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct SocReport {
49    /// Unique identifier for this report
50    pub id: String,
51    /// Reference to the service organization
52    pub service_org_id: String,
53    /// Type of SOC report
54    pub report_type: SocReportType,
55    /// Start of the period covered by the report
56    pub report_period_start: NaiveDate,
57    /// End of the period covered by the report
58    pub report_period_end: NaiveDate,
59    /// Opinion issued by the service auditor
60    pub opinion_type: SocOpinionType,
61    /// Control objectives included in the report
62    pub control_objectives: Vec<ControlObjective>,
63    /// Exceptions noted during testing
64    pub exceptions_noted: Vec<SocException>,
65}
66
67/// SOC report type.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
69#[serde(rename_all = "snake_case")]
70pub enum SocReportType {
71    /// SOC 1 Type I: design of controls at a point in time
72    Soc1Type1,
73    /// SOC 1 Type II: design and operating effectiveness over a period
74    #[default]
75    Soc1Type2,
76}
77
78/// Opinion issued by the service auditor on the SOC report.
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
80#[serde(rename_all = "snake_case")]
81pub enum SocOpinionType {
82    /// Unmodified opinion — controls are suitably designed and operating effectively
83    #[default]
84    Unmodified,
85    /// Qualified opinion — one or more control objectives have exceptions
86    Qualified,
87    /// Adverse opinion — controls are not suitably designed or not operating effectively
88    Adverse,
89}
90
91/// A control objective within a SOC report.
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct ControlObjective {
94    /// Unique identifier for this objective
95    pub id: String,
96    /// Description of the control objective
97    pub description: String,
98    /// Number of controls tested against this objective
99    pub controls_tested: u32,
100    /// Whether all tested controls operated effectively
101    pub controls_effective: bool,
102}
103
104/// An exception noted during SOC report testing.
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct SocException {
107    /// ID of the control objective to which this exception relates
108    pub control_objective_id: String,
109    /// Description of the exception
110    pub description: String,
111    /// Service organization's management response to the exception
112    pub management_response: String,
113    /// Impact assessment for the user entity
114    pub user_entity_impact: String,
115}
116
117/// A complementary user entity control (CUEC) mapped to a SOC objective.
118///
119/// User entities are responsible for implementing certain controls to complement
120/// the controls at the service organization.  These are documented by the user
121/// auditor per ISA 402 requirements.
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct UserEntityControl {
124    /// Unique identifier
125    pub id: String,
126    /// Reference to the SOC report this control relates to
127    pub soc_report_id: String,
128    /// Description of the user entity control
129    pub description: String,
130    /// ID of the SOC control objective this control maps to
131    pub mapped_objective: String,
132    /// Whether the control has been implemented
133    pub implemented: bool,
134    /// Operating effectiveness assessment
135    pub operating_effectiveness: ControlEffectiveness,
136}
137
138/// Operating effectiveness assessment for a user entity control.
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
140#[serde(rename_all = "snake_case")]
141pub enum ControlEffectiveness {
142    /// Control is operating effectively
143    #[default]
144    Effective,
145    /// Control has minor exceptions but is substantially effective
146    EffectiveWithExceptions,
147    /// Control is not operating effectively
148    Ineffective,
149    /// Control has not been tested
150    NotTested,
151}
152
153impl ServiceOrganization {
154    /// Create a new service organization.
155    pub fn new(
156        name: impl Into<String>,
157        service_type: ServiceType,
158        entities_served: Vec<String>,
159    ) -> Self {
160        Self {
161            id: Uuid::new_v4().to_string(),
162            name: name.into(),
163            service_type,
164            entities_served,
165        }
166    }
167}
168
169impl SocReport {
170    /// Create a new SOC report.
171    pub fn new(
172        service_org_id: impl Into<String>,
173        report_type: SocReportType,
174        report_period_start: NaiveDate,
175        report_period_end: NaiveDate,
176        opinion_type: SocOpinionType,
177    ) -> Self {
178        Self {
179            id: Uuid::new_v4().to_string(),
180            service_org_id: service_org_id.into(),
181            report_type,
182            report_period_start,
183            report_period_end,
184            opinion_type,
185            control_objectives: Vec::new(),
186            exceptions_noted: Vec::new(),
187        }
188    }
189}
190
191impl ControlObjective {
192    /// Create a new control objective.
193    pub fn new(
194        description: impl Into<String>,
195        controls_tested: u32,
196        controls_effective: bool,
197    ) -> Self {
198        Self {
199            id: Uuid::new_v4().to_string(),
200            description: description.into(),
201            controls_tested,
202            controls_effective,
203        }
204    }
205}
206
207impl UserEntityControl {
208    /// Create a new user entity control.
209    pub fn new(
210        soc_report_id: impl Into<String>,
211        description: impl Into<String>,
212        mapped_objective: impl Into<String>,
213        implemented: bool,
214        operating_effectiveness: ControlEffectiveness,
215    ) -> Self {
216        Self {
217            id: Uuid::new_v4().to_string(),
218            soc_report_id: soc_report_id.into(),
219            description: description.into(),
220            mapped_objective: mapped_objective.into(),
221            implemented,
222            operating_effectiveness,
223        }
224    }
225}