1use serde::{Deserialize, Serialize};
7
8use super::coso::{ControlScope, CosoComponent, CosoMaturityLevel, CosoPrinciple};
9use super::user::UserPersona;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum ControlType {
15 Preventive,
17 Detective,
19 Monitoring,
21}
22
23impl std::fmt::Display for ControlType {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 Self::Preventive => write!(f, "Preventive"),
27 Self::Detective => write!(f, "Detective"),
28 Self::Monitoring => write!(f, "Monitoring"),
29 }
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "snake_case")]
36pub enum ControlFrequency {
37 Transactional,
39 Daily,
41 Weekly,
43 Monthly,
45 Quarterly,
47 Annual,
49}
50
51impl std::fmt::Display for ControlFrequency {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 Self::Transactional => write!(f, "Transactional"),
55 Self::Daily => write!(f, "Daily"),
56 Self::Weekly => write!(f, "Weekly"),
57 Self::Monthly => write!(f, "Monthly"),
58 Self::Quarterly => write!(f, "Quarterly"),
59 Self::Annual => write!(f, "Annual"),
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
66#[serde(rename_all = "snake_case")]
67pub enum RiskLevel {
68 Low,
70 Medium,
72 High,
74 Critical,
76}
77
78impl std::fmt::Display for RiskLevel {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 match self {
81 Self::Low => write!(f, "Low"),
82 Self::Medium => write!(f, "Medium"),
83 Self::High => write!(f, "High"),
84 Self::Critical => write!(f, "Critical"),
85 }
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
91#[serde(rename_all = "snake_case")]
92pub enum SoxAssertion {
93 Existence,
95 Completeness,
97 Valuation,
99 RightsAndObligations,
101 PresentationAndDisclosure,
103}
104
105impl std::fmt::Display for SoxAssertion {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 match self {
108 Self::Existence => write!(f, "Existence"),
109 Self::Completeness => write!(f, "Completeness"),
110 Self::Valuation => write!(f, "Valuation"),
111 Self::RightsAndObligations => write!(f, "RightsAndObligations"),
112 Self::PresentationAndDisclosure => write!(f, "PresentationAndDisclosure"),
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
119#[serde(rename_all = "snake_case")]
120pub enum ControlStatus {
121 #[default]
123 Effective,
124 Exception,
126 NotTested,
128 Remediated,
130}
131
132impl std::fmt::Display for ControlStatus {
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 match self {
135 Self::Effective => write!(f, "Effective"),
136 Self::Exception => write!(f, "Exception"),
137 Self::NotTested => write!(f, "NotTested"),
138 Self::Remediated => write!(f, "Remediated"),
139 }
140 }
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct InternalControl {
146 pub control_id: String,
148 pub control_name: String,
150 pub control_type: ControlType,
152 pub objective: String,
154 pub frequency: ControlFrequency,
156 pub owner_role: UserPersona,
158 pub risk_level: RiskLevel,
160 pub description: String,
162 pub is_key_control: bool,
164 pub sox_assertion: SoxAssertion,
166 pub coso_component: CosoComponent,
168 pub coso_principles: Vec<CosoPrinciple>,
170 pub control_scope: ControlScope,
172 pub maturity_level: CosoMaturityLevel,
174}
175
176impl InternalControl {
177 pub fn new(
179 control_id: impl Into<String>,
180 control_name: impl Into<String>,
181 control_type: ControlType,
182 objective: impl Into<String>,
183 ) -> Self {
184 Self {
185 control_id: control_id.into(),
186 control_name: control_name.into(),
187 control_type,
188 objective: objective.into(),
189 frequency: ControlFrequency::Transactional,
190 owner_role: UserPersona::Controller,
191 risk_level: RiskLevel::Medium,
192 description: String::new(),
193 is_key_control: false,
194 sox_assertion: SoxAssertion::Existence,
195 coso_component: CosoComponent::ControlActivities,
196 coso_principles: vec![CosoPrinciple::ControlActions],
197 control_scope: ControlScope::TransactionLevel,
198 maturity_level: CosoMaturityLevel::Defined,
199 }
200 }
201
202 pub fn with_frequency(mut self, frequency: ControlFrequency) -> Self {
204 self.frequency = frequency;
205 self
206 }
207
208 pub fn with_owner(mut self, owner: UserPersona) -> Self {
210 self.owner_role = owner;
211 self
212 }
213
214 pub fn with_risk_level(mut self, level: RiskLevel) -> Self {
216 self.risk_level = level;
217 self
218 }
219
220 pub fn with_description(mut self, description: impl Into<String>) -> Self {
222 self.description = description.into();
223 self
224 }
225
226 pub fn as_key_control(mut self) -> Self {
228 self.is_key_control = true;
229 self
230 }
231
232 pub fn with_assertion(mut self, assertion: SoxAssertion) -> Self {
234 self.sox_assertion = assertion;
235 self
236 }
237
238 pub fn with_coso_component(mut self, component: CosoComponent) -> Self {
240 self.coso_component = component;
241 self
242 }
243
244 pub fn with_coso_principles(mut self, principles: Vec<CosoPrinciple>) -> Self {
246 self.coso_principles = principles;
247 self
248 }
249
250 pub fn with_control_scope(mut self, scope: ControlScope) -> Self {
252 self.control_scope = scope;
253 self
254 }
255
256 pub fn with_maturity_level(mut self, level: CosoMaturityLevel) -> Self {
258 self.maturity_level = level;
259 self
260 }
261
262 pub fn standard_controls() -> Vec<Self> {
267 vec![
268 Self::new(
274 "C001",
275 "Cash Account Daily Review",
276 ControlType::Detective,
277 "Review all cash transactions daily for unauthorized activity",
278 )
279 .with_frequency(ControlFrequency::Daily)
280 .with_owner(UserPersona::Controller)
281 .with_risk_level(RiskLevel::High)
282 .as_key_control()
283 .with_assertion(SoxAssertion::Existence)
284 .with_description(
285 "Daily reconciliation of cash accounts with bank statements and review of unusual transactions",
286 )
287 .with_coso_component(CosoComponent::ControlActivities)
288 .with_coso_principles(vec![
289 CosoPrinciple::ControlActions,
290 CosoPrinciple::OngoingMonitoring,
291 ])
292 .with_control_scope(ControlScope::TransactionLevel)
293 .with_maturity_level(CosoMaturityLevel::Managed),
294
295 Self::new(
297 "C002",
298 "Large Transaction Multi-Level Approval",
299 ControlType::Preventive,
300 "Transactions over $10,000 require additional approval levels",
301 )
302 .with_frequency(ControlFrequency::Transactional)
303 .with_owner(UserPersona::Manager)
304 .with_risk_level(RiskLevel::High)
305 .as_key_control()
306 .with_assertion(SoxAssertion::Valuation)
307 .with_description(
308 "Multi-level approval workflow for transactions exceeding defined thresholds",
309 )
310 .with_coso_component(CosoComponent::ControlActivities)
311 .with_coso_principles(vec![
312 CosoPrinciple::ControlActions,
313 CosoPrinciple::PoliciesAndProcedures,
314 ])
315 .with_control_scope(ControlScope::TransactionLevel)
316 .with_maturity_level(CosoMaturityLevel::Defined),
317
318 Self::new(
320 "C010",
321 "Three-Way Match",
322 ControlType::Preventive,
323 "Match purchase order, receipt, and invoice before payment",
324 )
325 .with_frequency(ControlFrequency::Transactional)
326 .with_owner(UserPersona::SeniorAccountant)
327 .with_risk_level(RiskLevel::Medium)
328 .as_key_control()
329 .with_assertion(SoxAssertion::Completeness)
330 .with_description(
331 "Automated matching of PO, goods receipt, and vendor invoice prior to payment release",
332 )
333 .with_coso_component(CosoComponent::ControlActivities)
334 .with_coso_principles(vec![
335 CosoPrinciple::ControlActions,
336 CosoPrinciple::TechnologyControls,
337 ])
338 .with_control_scope(ControlScope::ItApplicationControl)
339 .with_maturity_level(CosoMaturityLevel::Managed),
340
341 Self::new(
343 "C011",
344 "Vendor Master Data Maintenance",
345 ControlType::Preventive,
346 "Segregated access for vendor master data changes",
347 )
348 .with_frequency(ControlFrequency::Transactional)
349 .with_owner(UserPersona::SeniorAccountant)
350 .with_risk_level(RiskLevel::High)
351 .as_key_control()
352 .with_assertion(SoxAssertion::Existence)
353 .with_description(
354 "Restricted access to vendor master data with dual-approval for bank account changes",
355 )
356 .with_coso_component(CosoComponent::ControlActivities)
357 .with_coso_principles(vec![
358 CosoPrinciple::ControlActions,
359 CosoPrinciple::FraudRisk,
360 ])
361 .with_control_scope(ControlScope::TransactionLevel)
362 .with_maturity_level(CosoMaturityLevel::Defined),
363
364 Self::new(
366 "C020",
367 "Revenue Recognition Review",
368 ControlType::Detective,
369 "Review revenue entries for proper timing and classification",
370 )
371 .with_frequency(ControlFrequency::Monthly)
372 .with_owner(UserPersona::Controller)
373 .with_risk_level(RiskLevel::Critical)
374 .as_key_control()
375 .with_assertion(SoxAssertion::Valuation)
376 .with_description(
377 "Monthly review of revenue recognition to ensure compliance with ASC 606",
378 )
379 .with_coso_component(CosoComponent::ControlActivities)
380 .with_coso_principles(vec![
381 CosoPrinciple::ControlActions,
382 CosoPrinciple::ClearObjectives,
383 ])
384 .with_control_scope(ControlScope::TransactionLevel)
385 .with_maturity_level(CosoMaturityLevel::Managed),
386
387 Self::new(
389 "C021",
390 "Customer Credit Limit Check",
391 ControlType::Preventive,
392 "Automatic credit limit check before order acceptance",
393 )
394 .with_frequency(ControlFrequency::Transactional)
395 .with_owner(UserPersona::AutomatedSystem)
396 .with_risk_level(RiskLevel::Medium)
397 .with_assertion(SoxAssertion::Valuation)
398 .with_description(
399 "System-enforced credit limit validation at order entry",
400 )
401 .with_coso_component(CosoComponent::ControlActivities)
402 .with_coso_principles(vec![
403 CosoPrinciple::TechnologyControls,
404 CosoPrinciple::ControlActions,
405 ])
406 .with_control_scope(ControlScope::ItApplicationControl)
407 .with_maturity_level(CosoMaturityLevel::Optimized),
408
409 Self::new(
411 "C030",
412 "GL Account Reconciliation",
413 ControlType::Detective,
414 "Monthly reconciliation of all balance sheet accounts",
415 )
416 .with_frequency(ControlFrequency::Monthly)
417 .with_owner(UserPersona::SeniorAccountant)
418 .with_risk_level(RiskLevel::High)
419 .as_key_control()
420 .with_assertion(SoxAssertion::Completeness)
421 .with_description(
422 "Complete reconciliation of all balance sheet accounts with supporting documentation",
423 )
424 .with_coso_component(CosoComponent::MonitoringActivities)
425 .with_coso_principles(vec![CosoPrinciple::OngoingMonitoring])
426 .with_control_scope(ControlScope::TransactionLevel)
427 .with_maturity_level(CosoMaturityLevel::Managed),
428
429 Self::new(
431 "C031",
432 "Manual Journal Entry Review",
433 ControlType::Detective,
434 "Review of all manual journal entries over threshold",
435 )
436 .with_frequency(ControlFrequency::Daily)
437 .with_owner(UserPersona::Controller)
438 .with_risk_level(RiskLevel::High)
439 .as_key_control()
440 .with_assertion(SoxAssertion::Existence)
441 .with_description(
442 "Daily review of manual journal entries with supporting documentation",
443 )
444 .with_coso_component(CosoComponent::ControlActivities)
445 .with_coso_principles(vec![
446 CosoPrinciple::ControlActions,
447 CosoPrinciple::FraudRisk,
448 ])
449 .with_control_scope(ControlScope::TransactionLevel)
450 .with_maturity_level(CosoMaturityLevel::Managed),
451
452 Self::new(
454 "C032",
455 "Period Close Checklist",
456 ControlType::Detective,
457 "Comprehensive checklist for period-end close procedures",
458 )
459 .with_frequency(ControlFrequency::Monthly)
460 .with_owner(UserPersona::Controller)
461 .with_risk_level(RiskLevel::Medium)
462 .with_assertion(SoxAssertion::Completeness)
463 .with_description(
464 "Standardized period-end close checklist ensuring all procedures completed",
465 )
466 .with_coso_component(CosoComponent::ControlActivities)
467 .with_coso_principles(vec![
468 CosoPrinciple::PoliciesAndProcedures,
469 CosoPrinciple::ControlActions,
470 ])
471 .with_control_scope(ControlScope::TransactionLevel)
472 .with_maturity_level(CosoMaturityLevel::Defined),
473
474 Self::new(
476 "C040",
477 "Payroll Processing Review",
478 ControlType::Detective,
479 "Review of payroll processing for accuracy",
480 )
481 .with_frequency(ControlFrequency::Monthly)
482 .with_owner(UserPersona::Controller)
483 .with_risk_level(RiskLevel::High)
484 .as_key_control()
485 .with_assertion(SoxAssertion::Valuation)
486 .with_description(
487 "Monthly review of payroll journals and reconciliation to HR records",
488 )
489 .with_coso_component(CosoComponent::ControlActivities)
490 .with_coso_principles(vec![
491 CosoPrinciple::ControlActions,
492 CosoPrinciple::FraudRisk,
493 ])
494 .with_control_scope(ControlScope::TransactionLevel)
495 .with_maturity_level(CosoMaturityLevel::Managed),
496
497 Self::new(
499 "C050",
500 "Fixed Asset Addition Approval",
501 ControlType::Preventive,
502 "Multi-level approval for capital expenditures",
503 )
504 .with_frequency(ControlFrequency::Transactional)
505 .with_owner(UserPersona::Manager)
506 .with_risk_level(RiskLevel::Medium)
507 .with_assertion(SoxAssertion::Existence)
508 .with_description(
509 "Approval workflow for capital asset additions based on dollar thresholds",
510 )
511 .with_coso_component(CosoComponent::ControlActivities)
512 .with_coso_principles(vec![
513 CosoPrinciple::ControlActions,
514 CosoPrinciple::PoliciesAndProcedures,
515 ])
516 .with_control_scope(ControlScope::TransactionLevel)
517 .with_maturity_level(CosoMaturityLevel::Defined),
518
519 Self::new(
521 "C060",
522 "Intercompany Balance Reconciliation",
523 ControlType::Detective,
524 "Monthly reconciliation of intercompany balances",
525 )
526 .with_frequency(ControlFrequency::Monthly)
527 .with_owner(UserPersona::SeniorAccountant)
528 .with_risk_level(RiskLevel::High)
529 .as_key_control()
530 .with_assertion(SoxAssertion::Completeness)
531 .with_description(
532 "Full reconciliation of intercompany accounts between all entities",
533 )
534 .with_coso_component(CosoComponent::MonitoringActivities)
535 .with_coso_principles(vec![
536 CosoPrinciple::OngoingMonitoring,
537 CosoPrinciple::DeficiencyEvaluation,
538 ])
539 .with_control_scope(ControlScope::TransactionLevel)
540 .with_maturity_level(CosoMaturityLevel::Managed),
541
542 Self::new(
548 "C070",
549 "Code of Conduct and Ethics",
550 ControlType::Preventive,
551 "Establish and communicate ethical values and standards of conduct",
552 )
553 .with_frequency(ControlFrequency::Annual)
554 .with_owner(UserPersona::Controller)
555 .with_risk_level(RiskLevel::High)
556 .as_key_control()
557 .with_assertion(SoxAssertion::PresentationAndDisclosure)
558 .with_description(
559 "Annual review and acknowledgment of code of conduct by all employees; \
560 includes ethics hotline and whistleblower protections",
561 )
562 .with_coso_component(CosoComponent::ControlEnvironment)
563 .with_coso_principles(vec![
564 CosoPrinciple::IntegrityAndEthics,
565 CosoPrinciple::Accountability,
566 ])
567 .with_control_scope(ControlScope::EntityLevel)
568 .with_maturity_level(CosoMaturityLevel::Managed),
569
570 Self::new(
572 "C071",
573 "Audit Committee Oversight",
574 ControlType::Monitoring,
575 "Board and audit committee exercise independent oversight of internal control",
576 )
577 .with_frequency(ControlFrequency::Quarterly)
578 .with_owner(UserPersona::Controller)
579 .with_risk_level(RiskLevel::Critical)
580 .as_key_control()
581 .with_assertion(SoxAssertion::PresentationAndDisclosure)
582 .with_description(
583 "Quarterly audit committee meetings with review of internal control effectiveness, \
584 external auditor findings, and management representations",
585 )
586 .with_coso_component(CosoComponent::ControlEnvironment)
587 .with_coso_principles(vec![
588 CosoPrinciple::BoardOversight,
589 CosoPrinciple::OrganizationalStructure,
590 ])
591 .with_control_scope(ControlScope::EntityLevel)
592 .with_maturity_level(CosoMaturityLevel::Managed),
593
594 Self::new(
596 "C075",
597 "Enterprise Risk Assessment",
598 ControlType::Detective,
599 "Identify and assess risks to achievement of organizational objectives",
600 )
601 .with_frequency(ControlFrequency::Annual)
602 .with_owner(UserPersona::Controller)
603 .with_risk_level(RiskLevel::High)
604 .as_key_control()
605 .with_assertion(SoxAssertion::Completeness)
606 .with_description(
607 "Annual enterprise risk assessment process including fraud risk evaluation; \
608 risk register maintained and updated quarterly",
609 )
610 .with_coso_component(CosoComponent::RiskAssessment)
611 .with_coso_principles(vec![
612 CosoPrinciple::IdentifyRisks,
613 CosoPrinciple::FraudRisk,
614 CosoPrinciple::ChangeIdentification,
615 ])
616 .with_control_scope(ControlScope::EntityLevel)
617 .with_maturity_level(CosoMaturityLevel::Defined),
618
619 Self::new(
621 "C077",
622 "IT General Controls Program",
623 ControlType::Preventive,
624 "General controls over IT environment supporting financial reporting systems",
625 )
626 .with_frequency(ControlFrequency::Transactional)
627 .with_owner(UserPersona::AutomatedSystem)
628 .with_risk_level(RiskLevel::High)
629 .as_key_control()
630 .with_assertion(SoxAssertion::Existence)
631 .with_description(
632 "IT general controls including access management, change management, \
633 computer operations, and program development for systems supporting \
634 financial reporting",
635 )
636 .with_coso_component(CosoComponent::ControlActivities)
637 .with_coso_principles(vec![
638 CosoPrinciple::TechnologyControls,
639 CosoPrinciple::PoliciesAndProcedures,
640 ])
641 .with_control_scope(ControlScope::ItGeneralControl)
642 .with_maturity_level(CosoMaturityLevel::Managed),
643
644 Self::new(
646 "C078",
647 "Financial Information Quality",
648 ControlType::Detective,
649 "Obtain and use quality information for internal control",
650 )
651 .with_frequency(ControlFrequency::Monthly)
652 .with_owner(UserPersona::Controller)
653 .with_risk_level(RiskLevel::Medium)
654 .with_assertion(SoxAssertion::Valuation)
655 .with_description(
656 "Monthly data quality reviews for key financial reports; validation of \
657 data inputs, processing, and outputs supporting management decisions",
658 )
659 .with_coso_component(CosoComponent::InformationCommunication)
660 .with_coso_principles(vec![
661 CosoPrinciple::QualityInformation,
662 CosoPrinciple::InternalCommunication,
663 ])
664 .with_control_scope(ControlScope::EntityLevel)
665 .with_maturity_level(CosoMaturityLevel::Defined),
666
667 Self::new(
669 "C081",
670 "Internal Control Monitoring Program",
671 ControlType::Monitoring,
672 "Ongoing and periodic evaluations of internal control effectiveness",
673 )
674 .with_frequency(ControlFrequency::Quarterly)
675 .with_owner(UserPersona::Controller)
676 .with_risk_level(RiskLevel::High)
677 .as_key_control()
678 .with_assertion(SoxAssertion::Completeness)
679 .with_description(
680 "Continuous monitoring program with quarterly control testing, \
681 deficiency tracking, and remediation management; annual SOX 404 \
682 assessment and certification",
683 )
684 .with_coso_component(CosoComponent::MonitoringActivities)
685 .with_coso_principles(vec![
686 CosoPrinciple::OngoingMonitoring,
687 CosoPrinciple::DeficiencyEvaluation,
688 ])
689 .with_control_scope(ControlScope::EntityLevel)
690 .with_maturity_level(CosoMaturityLevel::Managed),
691 ]
692 }
693}
694
695#[cfg(test)]
696mod tests {
697 use super::*;
698
699 #[test]
700 fn test_control_creation() {
701 let control = InternalControl::new(
702 "TEST001",
703 "Test Control",
704 ControlType::Preventive,
705 "Test objective",
706 )
707 .with_frequency(ControlFrequency::Daily)
708 .with_risk_level(RiskLevel::High)
709 .as_key_control();
710
711 assert_eq!(control.control_id, "TEST001");
712 assert_eq!(control.control_type, ControlType::Preventive);
713 assert_eq!(control.frequency, ControlFrequency::Daily);
714 assert_eq!(control.risk_level, RiskLevel::High);
715 assert!(control.is_key_control);
716 }
717
718 #[test]
719 fn test_standard_controls() {
720 let controls = InternalControl::standard_controls();
721 assert!(!controls.is_empty());
722
723 let key_controls: Vec<_> = controls.iter().filter(|c| c.is_key_control).collect();
725 assert!(key_controls.len() >= 5);
726
727 let preventive: Vec<_> = controls
729 .iter()
730 .filter(|c| c.control_type == ControlType::Preventive)
731 .collect();
732 let detective: Vec<_> = controls
733 .iter()
734 .filter(|c| c.control_type == ControlType::Detective)
735 .collect();
736
737 assert!(!preventive.is_empty());
738 assert!(!detective.is_empty());
739 }
740
741 #[test]
742 fn test_control_status_display() {
743 assert_eq!(ControlStatus::Effective.to_string(), "Effective");
744 assert_eq!(ControlStatus::Exception.to_string(), "Exception");
745 }
746}