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}