1use super::{AnimalId, Date, DateRange, IsoDate, Limit, LocationId, Method, OwnerId, Request};
2
3pub mod reservation {
5 use super::*;
6
7 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
8 pub struct TypeId(u64);
10
11 impl TypeId {
12 pub const fn new(value: u64) -> Self {
14 Self(value)
15 }
16 }
17
18 impl core::fmt::Display for TypeId {
19 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
20 write!(formatter, "{}", self.0)
21 }
22 }
23
24 #[derive(Clone, Debug, Default, PartialEq, Eq)]
25 pub struct Types {
27 id: Option<TypeId>,
28 active_only: Option<bool>,
29 }
30
31 impl Types {
32 pub fn builder() -> TypesBuilder {
34 TypesBuilder::default()
35 }
36 }
37
38 #[derive(Clone, Debug, Default)]
39 pub struct TypesBuilder {
41 id: Option<TypeId>,
42 active_only: Option<bool>,
43 }
44
45 impl TypesBuilder {
46 pub fn id(mut self, id: TypeId) -> Self {
48 self.id = Some(id);
49 self
50 }
51
52 pub fn active_only(mut self, active_only: bool) -> Self {
54 self.active_only = Some(active_only);
55 self
56 }
57
58 pub fn build(self) -> Types {
60 Types {
61 id: self.id,
62 active_only: self.active_only,
63 }
64 }
65 }
66
67 impl Request for Types {
68 fn method(&self) -> Method {
69 Method::Get
70 }
71
72 fn path(&self) -> &'static str {
73 "/api/v1/reservation_types"
74 }
75
76 fn parameters(&self) -> Vec<(String, String)> {
77 let mut params = Vec::new();
78 if let Some(id) = self.id {
79 params.push(("id".to_owned(), id.to_string()));
80 }
81 if let Some(active_only) = self.active_only {
82 params.push(("active_only".to_owned(), active_only.to_string()));
83 }
84 params
85 }
86 }
87
88 #[derive(Clone, Debug, PartialEq, Eq)]
89 pub struct WidgetData {
91 timestamp: Date,
92 }
93
94 impl WidgetData {
95 pub fn builder() -> WidgetDataBuilder {
97 WidgetDataBuilder::default()
98 }
99 }
100
101 #[derive(Clone, Debug, Default)]
102 pub struct WidgetDataBuilder {
104 timestamp: Option<Date>,
105 }
106
107 impl WidgetDataBuilder {
108 pub fn timestamp(mut self, timestamp: Date) -> Self {
110 self.timestamp = Some(timestamp);
111 self
112 }
113
114 pub fn build(self) -> WidgetData {
116 WidgetData {
117 timestamp: self.timestamp.expect("WidgetData requires timestamp"),
118 }
119 }
120 }
121
122 impl Request for WidgetData {
123 fn method(&self) -> Method {
124 Method::Get
125 }
126
127 fn path(&self) -> &'static str {
128 "/api/v1/reservation_widget_data"
129 }
130
131 fn parameters(&self) -> Vec<(String, String)> {
132 vec![("timestamp".to_owned(), self.timestamp.to_string())]
133 }
134 }
135
136 #[derive(Clone, Debug, Default, PartialEq, Eq)]
137 pub struct SearchFilters {
139 from_date: Option<IsoDate>,
140 to_date: Option<IsoDate>,
141 reservation_type_ids: Vec<TypeId>,
142 animal_ids: Vec<AnimalId>,
143 cancelled_only: Option<bool>,
144 confirmed_only: Option<bool>,
145 completed_only: Option<bool>,
146 limit: Option<Limit>,
147 }
148
149 impl SearchFilters {
150 pub fn builder() -> SearchFiltersBuilder {
152 SearchFiltersBuilder::default()
153 }
154
155 pub(super) fn parameters(&self) -> Vec<(String, String)> {
156 let mut params = Vec::new();
157 if let Some(from_date) = self.from_date {
158 params.push(("params[fromDate]".to_owned(), from_date.to_string()));
159 }
160 if let Some(to_date) = self.to_date {
161 params.push(("params[toDate]".to_owned(), to_date.to_string()));
162 }
163 for id in &self.reservation_type_ids {
164 params.push(("params[reservationTypeIds][]".to_owned(), id.to_string()));
165 }
166 for id in &self.animal_ids {
167 params.push(("params[animalIds][]".to_owned(), id.to_string()));
168 }
169 if let Some(value) = self.cancelled_only {
170 params.push(("params[cancelledOnly]".to_owned(), value.to_string()));
171 }
172 if let Some(value) = self.confirmed_only {
173 params.push(("params[confirmedOnly]".to_owned(), value.to_string()));
174 }
175 if let Some(value) = self.completed_only {
176 params.push(("params[completedOnly]".to_owned(), value.to_string()));
177 }
178 if let Some(limit) = self.limit {
179 params.push(("params[limit]".to_owned(), limit.to_string()));
180 }
181 params
182 }
183 }
184
185 #[derive(Clone, Debug, Default)]
186 pub struct SearchFiltersBuilder {
188 filters: SearchFilters,
189 }
190
191 impl SearchFiltersBuilder {
192 pub fn from_date(mut self, date: IsoDate) -> Self {
194 self.filters.from_date = Some(date);
195 self
196 }
197
198 pub fn to_date(mut self, date: IsoDate) -> Self {
200 self.filters.to_date = Some(date);
201 self
202 }
203
204 pub fn reservation_type_id(mut self, id: TypeId) -> Self {
206 self.filters.reservation_type_ids.push(id);
207 self
208 }
209
210 pub fn animal_id(mut self, id: AnimalId) -> Self {
212 self.filters.animal_ids.push(id);
213 self
214 }
215
216 pub fn cancelled_only(mut self, value: bool) -> Self {
218 self.filters.cancelled_only = Some(value);
219 self
220 }
221
222 pub fn confirmed_only(mut self, value: bool) -> Self {
224 self.filters.confirmed_only = Some(value);
225 self
226 }
227
228 pub fn completed_only(mut self, value: bool) -> Self {
230 self.filters.completed_only = Some(value);
231 self
232 }
233
234 pub fn limit(mut self, limit: Limit) -> Self {
236 self.filters.limit = Some(limit);
237 self
238 }
239
240 pub fn build(self) -> SearchFilters {
242 self.filters
243 }
244 }
245}
246
247#[derive(Clone, Debug, PartialEq, Eq)]
248pub struct Reservations {
250 checked_in: bool,
251 range: Option<DateRange>,
252 location: Option<LocationId>,
253}
254
255impl Reservations {
256 pub fn checked_in() -> Builder {
258 Builder {
259 checked_in: true,
260 range: None,
261 location: None,
262 }
263 }
264
265 pub fn for_range(range: DateRange) -> Builder {
267 Builder {
268 checked_in: false,
269 range: Some(range),
270 location: None,
271 }
272 }
273}
274
275#[derive(Clone, Debug, PartialEq, Eq)]
276pub struct Builder {
278 checked_in: bool,
279 range: Option<DateRange>,
280 location: Option<LocationId>,
281}
282
283impl Builder {
284 pub fn location(mut self, location: LocationId) -> Self {
286 self.location = Some(location);
287 self
288 }
289
290 pub fn build(self) -> Reservations {
292 Reservations {
293 checked_in: self.checked_in,
294 range: self.range,
295 location: self.location,
296 }
297 }
298}
299
300impl Request for Reservations {
301 fn method(&self) -> Method {
302 Method::Post
303 }
304
305 fn path(&self) -> &'static str {
306 "/api/v1/reservations"
307 }
308
309 fn parameters(&self) -> Vec<(String, String)> {
310 let mut params = vec![("checked_in".to_owned(), self.checked_in.to_string())];
311 if let Some(range) = self.range {
312 params.push(("start_date".to_owned(), range.start().to_string()));
313 params.push(("end_date".to_owned(), range.end().to_string()));
314 }
315 if let Some(location) = self.location {
316 params.push(("location_id".to_owned(), location.to_string()));
317 }
318 params
319 }
320}
321
322#[derive(Clone, Copy, Debug, PartialEq, Eq)]
323pub enum RestrictTo {
325 PendingRequests,
327 CurrentlyCheckedIn,
329 Future,
331 Past,
333 WaitListed,
335}
336
337impl core::fmt::Display for RestrictTo {
338 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
339 let value = match self {
340 Self::PendingRequests => "pending_requests",
341 Self::CurrentlyCheckedIn => "currently_checked_in",
342 Self::Future => "future",
343 Self::Past => "past",
344 Self::WaitListed => "wait_listed",
345 };
346 formatter.write_str(value)
347 }
348}
349
350pub mod by {
352 use super::*;
353
354 #[derive(Clone, Debug, PartialEq, Eq)]
355 pub struct Animal {
357 animal_id: AnimalId,
358 restrict_to: Option<RestrictTo>,
359 filters: Option<reservation::SearchFilters>,
360 }
361
362 impl Animal {
363 pub const LOCATION_SCOPE_CAVEAT: &'static str = "Reservation data for this endpoint is only pulled for the location the API user is currently logged into.";
365
366 pub fn builder() -> AnimalBuilder {
368 AnimalBuilder::default()
369 }
370 }
371
372 #[derive(Clone, Debug, Default)]
373 pub struct AnimalBuilder {
375 animal_id: Option<AnimalId>,
376 restrict_to: Option<RestrictTo>,
377 filters: Option<reservation::SearchFilters>,
378 }
379
380 impl AnimalBuilder {
381 pub fn animal_id(mut self, id: AnimalId) -> Self {
383 self.animal_id = Some(id);
384 self
385 }
386
387 pub fn restrict_to(mut self, restrict_to: RestrictTo) -> Self {
389 self.restrict_to = Some(restrict_to);
390 self
391 }
392
393 pub fn filter(mut self, filters: reservation::SearchFilters) -> Self {
395 self.filters = Some(filters);
396 self
397 }
398
399 pub fn build(self) -> Animal {
401 Animal {
402 animal_id: self.animal_id.expect("Animal requires animal_id"),
403 restrict_to: self.restrict_to,
404 filters: self.filters,
405 }
406 }
407 }
408
409 impl Request for Animal {
410 fn method(&self) -> Method {
411 Method::Post
412 }
413
414 fn path(&self) -> &'static str {
415 "/api/v1/reservations_by_animal"
416 }
417
418 fn parameters(&self) -> Vec<(String, String)> {
419 let mut params = vec![("id".to_owned(), self.animal_id.to_string())];
420 if let Some(restrict_to) = self.restrict_to {
421 params.push(("restrict_to".to_owned(), restrict_to.to_string()));
422 }
423 if let Some(filters) = &self.filters {
424 params.extend(filters.parameters());
425 }
426 params
427 }
428 }
429
430 #[derive(Clone, Debug, PartialEq, Eq)]
431 pub struct Owner {
433 owner_id: OwnerId,
434 restrict_to: Option<RestrictTo>,
435 filters: Option<reservation::SearchFilters>,
436 }
437
438 impl Owner {
439 pub const LOCATION_SCOPE_CAVEAT: &'static str = Animal::LOCATION_SCOPE_CAVEAT;
441
442 pub fn builder() -> OwnerBuilder {
444 OwnerBuilder::default()
445 }
446 }
447
448 #[derive(Clone, Debug, Default)]
449 pub struct OwnerBuilder {
451 owner_id: Option<OwnerId>,
452 restrict_to: Option<RestrictTo>,
453 filters: Option<reservation::SearchFilters>,
454 }
455
456 impl OwnerBuilder {
457 pub fn owner_id(mut self, id: OwnerId) -> Self {
459 self.owner_id = Some(id);
460 self
461 }
462
463 pub fn restrict_to(mut self, restrict_to: RestrictTo) -> Self {
465 self.restrict_to = Some(restrict_to);
466 self
467 }
468
469 pub fn filter(mut self, filters: reservation::SearchFilters) -> Self {
471 self.filters = Some(filters);
472 self
473 }
474
475 pub fn build(self) -> Owner {
477 Owner {
478 owner_id: self.owner_id.expect("Owner requires owner_id"),
479 restrict_to: self.restrict_to,
480 filters: self.filters,
481 }
482 }
483 }
484
485 impl Request for Owner {
486 fn method(&self) -> Method {
487 Method::Post
488 }
489
490 fn path(&self) -> &'static str {
491 "/api/v1/reservations_by_owner"
492 }
493
494 fn parameters(&self) -> Vec<(String, String)> {
495 let mut params = vec![("id".to_owned(), self.owner_id.to_string())];
496 if let Some(restrict_to) = self.restrict_to {
497 params.push(("restrict_to".to_owned(), restrict_to.to_string()));
498 }
499 if let Some(filters) = &self.filters {
500 params.extend(filters.parameters());
501 }
502 params
503 }
504 }
505}
506
507#[derive(Clone, Copy, Debug, PartialEq, Eq)]
508pub struct MinutesFuture(u64);
510
511impl MinutesFuture {
512 pub fn new(value: u64) -> super::Result<Self> {
514 if value == 0 {
515 return Err(super::Error::InvalidPositiveInteger { value });
516 }
517 Ok(Self(value))
518 }
519}
520
521impl core::fmt::Display for MinutesFuture {
522 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
523 write!(formatter, "{}", self.0)
524 }
525}
526
527#[derive(Clone, Debug, PartialEq, Eq)]
528pub struct BackOfHouse {
530 location: LocationId,
531 reservation_type_ids: Vec<reservation::TypeId>,
532 minutes_future: Option<MinutesFuture>,
533 full_day: Option<bool>,
534}
535
536impl BackOfHouse {
537 pub fn builder() -> BackOfHouseBuilder {
539 BackOfHouseBuilder::default()
540 }
541}
542
543#[derive(Clone, Debug, Default)]
544pub struct BackOfHouseBuilder {
546 location: Option<LocationId>,
547 reservation_type_ids: Vec<reservation::TypeId>,
548 minutes_future: Option<MinutesFuture>,
549 full_day: Option<bool>,
550}
551
552impl BackOfHouseBuilder {
553 pub fn location(mut self, location: LocationId) -> Self {
555 self.location = Some(location);
556 self
557 }
558
559 pub fn reservation_type_id(mut self, id: reservation::TypeId) -> Self {
561 self.reservation_type_ids.push(id);
562 self
563 }
564
565 pub fn minutes_future(mut self, minutes: MinutesFuture) -> Self {
567 self.minutes_future = Some(minutes);
568 self
569 }
570
571 pub fn full_day(mut self, full_day: bool) -> Self {
573 self.full_day = Some(full_day);
574 self
575 }
576
577 pub fn build(self) -> BackOfHouse {
579 BackOfHouse {
580 location: self.location.expect("BackOfHouse requires location"),
581 reservation_type_ids: self.reservation_type_ids,
582 minutes_future: self.minutes_future,
583 full_day: self.full_day,
584 }
585 }
586}
587
588impl Request for BackOfHouse {
589 fn method(&self) -> Method {
590 Method::Get
591 }
592
593 fn path(&self) -> &'static str {
594 "/api/v1/back_of_house"
595 }
596
597 fn parameters(&self) -> Vec<(String, String)> {
598 let mut params = vec![("location_id".to_owned(), self.location.to_string())];
599 for id in &self.reservation_type_ids {
600 params.push(("type_ids[]".to_owned(), id.to_string()));
601 }
602 if let Some(minutes) = self.minutes_future {
603 params.push(("mins_future".to_owned(), minutes.to_string()));
604 }
605 if let Some(full_day) = self.full_day {
606 params.push(("full_day".to_owned(), full_day.to_string()));
607 }
608 params
609 }
610}
611
612#[derive(Clone, Debug, PartialEq, Eq)]
613pub struct GetServicesByType {
615 type_id: reservation::TypeId,
616 location: Option<LocationId>,
617}
618
619impl GetServicesByType {
620 pub fn new(type_id: reservation::TypeId) -> Self {
622 Self {
623 type_id,
624 location: None,
625 }
626 }
627
628 pub fn location(mut self, location: LocationId) -> Self {
630 self.location = Some(location);
631 self
632 }
633}
634
635impl Request for GetServicesByType {
636 fn method(&self) -> Method {
637 Method::Get
638 }
639
640 fn path(&self) -> &'static str {
641 "/api/v1/get_services_by_type"
642 }
643
644 fn parameters(&self) -> Vec<(String, String)> {
645 let mut params = vec![("type_id".to_owned(), self.type_id.to_string())];
646 if let Some(location) = self.location {
647 params.push(("location_id".to_owned(), location.to_string()));
648 }
649 params
650 }
651}