1use bon::Builder;
12use serde::{Deserialize, Serialize};
13
14use crate::types::validate_fields;
15use crate::types::{CiString, DateTime, Extensions, Url, Validate, Validator, ViolationCode};
16
17use super::tokens::Token;
18
19pub use crate::v2_3_0::commands::{
21 CancelReservation, CommandResponse, CommandResponseType, CommandResult, CommandResultType, CommandType,
22 StopSession, UnlockConnector,
23};
24
25#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Builder)]
29#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
30#[builder(on(_, into))]
31pub struct StartSession {
32 pub response_url: Url,
34 pub token: Token,
36 pub location_id: CiString<36>,
38 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub evse_uid: Option<CiString<36>>,
41 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub connector_id: Option<CiString<36>>,
44 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub authorization_reference: Option<CiString<36>>,
47 #[serde(flatten, default, skip_serializing_if = "Extensions::is_empty")]
49 #[builder(default)]
50 pub extensions: Extensions,
51}
52
53impl Validate for StartSession {
54 fn validate_in(&self, v: &mut Validator) {
55 validate_fields!(
56 self,
57 v,
58 response_url,
59 token,
60 location_id,
61 evse_uid,
62 connector_id,
63 authorization_reference,
64 );
65 if self.connector_id.is_some() && self.evse_uid.is_none() {
66 v.report_at(
67 "evse_uid",
68 ViolationCode::MissingConditional,
69 "is required when `connector_id` is set",
70 );
71 }
72 }
73}
74
75#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Builder)]
79#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
80#[builder(on(_, into))]
81pub struct ReserveNow {
82 pub response_url: Url,
84 pub token: Token,
86 pub expiry_date: DateTime,
88 pub reservation_id: CiString<36>,
90 pub location_id: CiString<36>,
92 #[serde(default, skip_serializing_if = "Option::is_none")]
94 pub evse_uid: Option<CiString<36>>,
95 #[serde(default, skip_serializing_if = "Option::is_none")]
97 pub authorization_reference: Option<CiString<36>>,
98 #[serde(flatten, default, skip_serializing_if = "Extensions::is_empty")]
100 #[builder(default)]
101 pub extensions: Extensions,
102}
103
104impl Validate for ReserveNow {
105 fn validate_in(&self, v: &mut Validator) {
106 validate_fields!(
107 self,
108 v,
109 response_url,
110 token,
111 expiry_date,
112 reservation_id,
113 location_id,
114 evse_uid,
115 authorization_reference,
116 );
117 }
118}
119
120#[derive(Clone, Debug, PartialEq)]
122#[non_exhaustive]
123pub enum Command {
124 CancelReservation(CancelReservation),
126 ReserveNow(Box<ReserveNow>),
128 StartSession(Box<StartSession>),
130 StopSession(StopSession),
132 UnlockConnector(UnlockConnector),
134}
135
136impl Command {
137 #[must_use]
139 pub fn command_type(&self) -> CommandType {
140 match self {
141 Self::CancelReservation(_) => CommandType::CancelReservation,
142 Self::ReserveNow(_) => CommandType::ReserveNow,
143 Self::StartSession(_) => CommandType::StartSession,
144 Self::StopSession(_) => CommandType::StopSession,
145 Self::UnlockConnector(_) => CommandType::UnlockConnector,
146 }
147 }
148
149 #[must_use]
151 pub fn response_url(&self) -> &Url {
152 match self {
153 Self::CancelReservation(c) => &c.response_url,
154 Self::ReserveNow(c) => &c.response_url,
155 Self::StartSession(c) => &c.response_url,
156 Self::StopSession(c) => &c.response_url,
157 Self::UnlockConnector(c) => &c.response_url,
158 }
159 }
160}
161
162impl Validate for Command {
163 fn validate_in(&self, v: &mut Validator) {
164 match self {
165 Self::CancelReservation(c) => c.validate_in(v),
166 Self::ReserveNow(c) => c.validate_in(v),
167 Self::StartSession(c) => c.validate_in(v),
168 Self::StopSession(c) => c.validate_in(v),
169 Self::UnlockConnector(c) => c.validate_in(v),
170 }
171 }
172}