headless_lms_models/library/credit_registration/
student_facing_status.rs1use utoipa::ToSchema;
5
6use crate::credit_registrations::CreditRegistrationState;
7use crate::prelude::*;
8
9use super::pending_reason::{CreditRegistrationPendingReason, PendingPreconditions};
10
11#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Hash, ToSchema)]
13#[serde(rename_all = "snake_case")]
14pub enum StudentFacingCreditRegistrationStatus {
15 WaitingForCompletion,
16 NeedsStudentNumber,
17 InProgress,
18 NeedsEnrolment,
19 WaitingForSisu,
20 Registered,
21 Failed,
22 NotRegistering,
24}
25
26impl StudentFacingCreditRegistrationStatus {
27 pub fn of(state: CreditRegistrationState, preconditions: PendingPreconditions) -> Self {
31 use CreditRegistrationPendingReason as Reason;
32 use CreditRegistrationState as State;
33 match state {
34 State::Pending => match preconditions.reason() {
35 Some(Reason::Completion) => Self::WaitingForCompletion,
36 Some(Reason::StudentNumber) => Self::NeedsStudentNumber,
37 None => Self::InProgress,
39 },
40 State::ReadyToSubmit
41 | State::ResolvingEnrolment
42 | State::CheckingEnrolment
43 | State::Submitting
44 | State::FailedRetryable => Self::InProgress,
45 State::NoUsableEnrolment => Self::NeedsEnrolment,
46 State::SubmissionUncertain | State::AwaitingVerification => Self::WaitingForSisu,
47 State::Registered | State::Duplicate | State::NotImproved => Self::Registered,
49 State::Misregistered | State::FailedPermanent => Self::Failed,
50 State::Blocked | State::Cancelled => Self::NotRegistering,
51 }
52 }
53
54 pub fn is_moving(self) -> bool {
56 matches!(self, Self::InProgress | Self::WaitingForSisu)
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use CreditRegistrationState as State;
64 use StudentFacingCreditRegistrationStatus as Status;
65
66 #[test]
68 fn only_the_states_the_pipeline_still_owns_keep_the_page_polling() {
69 for reason in [
70 PendingPreconditions {
71 completion_eligible: false,
72 ..PendingPreconditions::ALL_MET
73 },
74 PendingPreconditions {
75 has_verified_student_number: false,
76 ..PendingPreconditions::ALL_MET
77 },
78 ] {
79 assert!(
80 !Status::of(State::Pending, reason).is_moving(),
81 "{reason:?}"
82 );
83 }
84 let moving = [
85 State::Pending,
87 State::ReadyToSubmit,
88 State::ResolvingEnrolment,
89 State::CheckingEnrolment,
90 State::Submitting,
91 State::FailedRetryable,
92 State::SubmissionUncertain,
93 State::AwaitingVerification,
94 ];
95 for state in CreditRegistrationState::ALL {
96 assert_eq!(
97 Status::of(state, PendingPreconditions::ALL_MET).is_moving(),
98 moving.contains(&state),
99 "{state:?}"
100 );
101 }
102 }
103
104 #[test]
106 fn the_success_set_is_one_stage() {
107 for state in CreditRegistrationState::ALL {
108 if state.is_success() {
109 assert_eq!(
110 Status::of(state, PendingPreconditions::ALL_MET),
111 Status::Registered,
112 "{state:?}"
113 );
114 }
115 }
116 }
117
118 #[test]
119 fn the_wire_spelling_is_snake_case() {
120 assert_eq!(
121 serde_json::to_value(Status::NeedsStudentNumber).unwrap(),
122 serde_json::json!("needs_student_number")
123 );
124 }
125}