status.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. use crate::MaxLengthString;
  2. use serde::{Deserialize, Serialize};
  3. use std::collections::HashMap;
  4. /// Status type
  5. ///
  6. /// The statuses are bare strings of at most 10 characters
  7. pub type Status = MaxLengthString<10>;
  8. #[derive(Debug, Serialize, Deserialize)]
  9. /// Status manager
  10. ///
  11. /// This struct manages the status of the payments and their life cycle.
  12. pub struct StatusManager {
  13. /// List of all statuses
  14. statuses: Vec<Status>,
  15. /// List of all spendable statuses
  16. spendable: Vec<Status>,
  17. /// The default spendable status
  18. default_spendable: Status,
  19. /// List of all reverted statuses
  20. reverted: Vec<Status>,
  21. transition: HashMap<Status, Vec<Status>>,
  22. }
  23. #[derive(Debug, Clone, Copy)]
  24. /// Internal status type
  25. ///
  26. /// There could be many statuses, but they are translated into three types:
  27. pub enum InternalStatus {
  28. /// The payment is spendable, because it is final and it has been successfully processed
  29. Spendable,
  30. /// The payment is reverted, because it has been cancelled or failed
  31. Reverted,
  32. /// The payment is not created but still not final, it may be visible or not on the account's
  33. /// balance, but it is not spendable
  34. Pending,
  35. }
  36. /// Status error object
  37. #[derive(Debug, Serialize, thiserror::Error)]
  38. pub enum Error {
  39. #[error("Unknown status: {0}")]
  40. UnknownStatus(String),
  41. #[error("Invalid transition from {0} to {1}")]
  42. InvalidTransition(Status, Status),
  43. }
  44. impl StatusManager {
  45. /// Creates a new status from a given string
  46. pub fn new_status(&self, status_name: &str) -> Result<Status, Error> {
  47. self.statuses
  48. .iter()
  49. .find(|status| *status == status_name)
  50. .cloned()
  51. .ok_or(Error::UnknownStatus(status_name.to_owned()))
  52. }
  53. /// Translated the status into an internal status type
  54. pub fn internal_type(&self, status: &Status) -> InternalStatus {
  55. if self.is_spendable(status) {
  56. InternalStatus::Spendable
  57. } else if self.is_reverted(status) {
  58. InternalStatus::Reverted
  59. } else {
  60. InternalStatus::Pending
  61. }
  62. }
  63. /// Whether the status is spendable or not
  64. pub fn spendables(&self) -> &[Status] {
  65. &self.spendable
  66. }
  67. /// Whether the status is reverted or not
  68. pub fn default_spendable(&self) -> Status {
  69. self.default_spendable.clone()
  70. }
  71. /// Spendable statuses are the final state of a transaction that has finished as successfully
  72. /// therefore it is spendable.
  73. pub fn is_spendable(&self, status: &Status) -> bool {
  74. self.spendable.contains(status)
  75. }
  76. /// Reverted transactions are the final state of a transaction that has failed or cancelled and
  77. /// they inputs payments are reverted and spendedable.
  78. pub fn is_reverted(&self, status: &Status) -> bool {
  79. self.reverted.contains(status)
  80. }
  81. /// The transaction is final and cannot longer be updated
  82. pub fn is_final(&self, status: &Status) -> bool {
  83. self.is_spendable(status) || self.is_reverted(status)
  84. }
  85. /// Checks if the status transition is allowed
  86. pub fn is_valid_transition(&self, from: &Status, to: &Status) -> Result<(), Error> {
  87. if self.transition.get(from).map_or(false, |v| v.contains(to)) {
  88. Ok(())
  89. } else {
  90. Err(Error::InvalidTransition(from.clone(), to.clone()))
  91. }
  92. }
  93. }
  94. impl Default for StatusManager {
  95. fn default() -> Self {
  96. let pending: Status = "pending".into();
  97. let processing: Status = "processing".into();
  98. let cancelled: Status = "cancelled".into();
  99. let settled: Status = "settled".into();
  100. let failed: Status = "failed".into();
  101. Self {
  102. statuses: vec![
  103. pending.clone(),
  104. processing.clone(),
  105. cancelled.clone(),
  106. settled.clone(),
  107. failed.clone(),
  108. ],
  109. default_spendable: settled.clone(),
  110. spendable: vec![settled.clone()],
  111. reverted: vec![cancelled.clone(), failed.clone()],
  112. transition: {
  113. let mut map = HashMap::new();
  114. map.insert(
  115. pending.clone(),
  116. vec![processing.clone(), settled.clone(), cancelled.clone()],
  117. );
  118. map.insert(processing.clone(), vec![settled, failed]);
  119. map
  120. },
  121. }
  122. }
  123. }