storage/service_line/
grooming.rs1use serde::{Deserialize, Deserializer, Serialize};
8
9use domain::grooming::rebooking;
10
11use crate::operations::{self, StorageField};
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(transparent)]
16pub struct ContractRecord(pub domain::grooming::Contract);
17
18impl From<domain::grooming::Contract> for ContractRecord {
19 fn from(value: domain::grooming::Contract) -> Self {
20 Self(value)
21 }
22}
23
24impl From<ContractRecord> for domain::grooming::Contract {
25 fn from(record: ContractRecord) -> Self {
26 record.0
27 }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
31#[serde(rename_all = "snake_case")]
32pub enum ServiceCode {
34 MiniGroom,
36 FullGroom,
38 ExitBath,
40 FullBath,
42 PremiumBath,
44 NailTrim,
46 NailDremel,
48 EarCleaning,
50 CoatSkinSpecificProduct,
52 FirstTimeGroomingOffer,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
57pub struct StoredCadenceWeeks(u8);
59
60impl StoredCadenceWeeks {
61 pub const fn try_new(value: u8) -> std::result::Result<Self, StoredCadenceWeeksError> {
63 if value == 0 {
64 return Err(StoredCadenceWeeksError::ZeroWeeks);
65 }
66 Ok(Self(value))
67 }
68
69 pub const fn get(self) -> u8 {
71 self.0
72 }
73}
74
75impl<'de> Deserialize<'de> for StoredCadenceWeeks {
76 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
77 where
78 D: Deserializer<'de>,
79 {
80 Self::try_new(u8::deserialize(deserializer)?).map_err(serde::de::Error::custom)
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
85pub enum StoredCadenceWeeksError {
87 #[error("stored grooming cadence requires at least one week")]
88 ZeroWeeks,
90}
91
92impl TryFrom<rebooking::CadenceWeeks> for StoredCadenceWeeks {
93 type Error = operations::Error;
94
95 fn try_from(value: rebooking::CadenceWeeks) -> operations::Result<Self> {
96 Self::try_new(value.get()).map_err(|err| operations::Error::InvalidDomainValue {
97 field: StorageField::GroomingCadenceWeeks,
98 reason: err.to_string(),
99 })
100 }
101}
102
103impl TryFrom<StoredCadenceWeeks> for rebooking::CadenceWeeks {
104 type Error = operations::Error;
105
106 fn try_from(value: StoredCadenceWeeks) -> operations::Result<Self> {
107 rebooking::CadenceWeeks::try_new(value.get()).map_err(|err| {
108 operations::Error::InvalidDomainValue {
109 field: StorageField::GroomingCadenceWeeks,
110 reason: err.to_string(),
111 }
112 })
113 }
114}
115
116impl From<ServiceCode> for domain::grooming::Service {
117 fn from(value: ServiceCode) -> Self {
118 match value {
119 ServiceCode::MiniGroom => Self::MiniGroom,
120 ServiceCode::FullGroom => Self::FullGroom,
121 ServiceCode::ExitBath => Self::ExitBath,
122 ServiceCode::FullBath => Self::FullBath,
123 ServiceCode::PremiumBath => Self::PremiumBath,
124 ServiceCode::NailTrim => Self::NailTrim,
125 ServiceCode::NailDremel => Self::NailDremel,
126 ServiceCode::EarCleaning => Self::EarCleaning,
127 ServiceCode::CoatSkinSpecificProduct => Self::CoatSkinSpecificProduct,
128 ServiceCode::FirstTimeGroomingOffer => Self::FirstTimeGroomingOffer,
129 }
130 }
131}
132
133impl From<domain::grooming::Service> for ServiceCode {
134 fn from(value: domain::grooming::Service) -> Self {
135 match value {
136 domain::grooming::Service::MiniGroom => Self::MiniGroom,
137 domain::grooming::Service::FullGroom => Self::FullGroom,
138 domain::grooming::Service::ExitBath => Self::ExitBath,
139 domain::grooming::Service::FullBath => Self::FullBath,
140 domain::grooming::Service::PremiumBath => Self::PremiumBath,
141 domain::grooming::Service::NailTrim => Self::NailTrim,
142 domain::grooming::Service::NailDremel => Self::NailDremel,
143 domain::grooming::Service::EarCleaning => Self::EarCleaning,
144 domain::grooming::Service::CoatSkinSpecificProduct => Self::CoatSkinSpecificProduct,
145 domain::grooming::Service::FirstTimeGroomingOffer => Self::FirstTimeGroomingOffer,
146 }
147 }
148}