1use super::{Date, Error, LocationId, Method, OwnerId, Request, Result};
2
3fn cutover_date() -> Date {
4 Date::parse("2019-08-01").expect("documented Gingr commerce cutover date is valid")
5}
6
7fn push_optional<T: core::fmt::Display>(
8 params: &mut Vec<(String, String)>,
9 key: &str,
10 value: Option<T>,
11) {
12 if let Some(value) = value {
13 params.push((key.to_owned(), value.to_string()));
14 }
15}
16
17pub mod get {
19 use super::*;
20
21 #[derive(Clone, Debug, Default, PartialEq, Eq)]
22 pub struct AllRetailItems;
24
25 impl Request for AllRetailItems {
26 fn method(&self) -> Method {
27 Method::Get
28 }
29
30 fn path(&self) -> &'static str {
31 "/api/v1/get_all_retail_items"
32 }
33
34 fn parameters(&self) -> Vec<(String, String)> {
35 Vec::new()
36 }
37 }
38
39 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
40 pub struct SubscriptionId(u64);
42
43 impl SubscriptionId {
44 pub fn new(value: u64) -> Self {
46 Self(value)
47 }
48 }
49
50 impl core::fmt::Display for SubscriptionId {
51 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 write!(formatter, "{}", self.0)
53 }
54 }
55
56 #[derive(Clone, Debug, PartialEq, Eq)]
57 pub struct Subscription {
59 id: SubscriptionId,
60 }
61
62 impl Subscription {
63 pub fn new(id: SubscriptionId) -> Self {
65 Self { id }
66 }
67 }
68
69 impl Request for Subscription {
70 fn method(&self) -> Method {
71 Method::Get
72 }
73
74 fn path(&self) -> &'static str {
75 "/api/v1/get_subscription"
76 }
77
78 fn parameters(&self) -> Vec<(String, String)> {
79 vec![("id".to_owned(), self.id.to_string())]
80 }
81 }
82
83 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
84 pub struct BillDayOfMonth(u8);
86
87 impl BillDayOfMonth {
88 pub fn new(value: u8) -> Result<Self> {
90 if (1..=31).contains(&value) {
91 Ok(Self(value))
92 } else {
93 Err(Error::InvalidBillDayOfMonth { value })
94 }
95 }
96 }
97
98 impl core::fmt::Display for BillDayOfMonth {
99 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 write!(formatter, "{}", self.0)
101 }
102 }
103
104 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
105 pub struct PackageId(u64);
107
108 impl PackageId {
109 pub fn new(value: u64) -> Self {
111 Self(value)
112 }
113 }
114
115 impl core::fmt::Display for PackageId {
116 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117 write!(formatter, "{}", self.0)
118 }
119 }
120
121 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
122 pub struct SubscriptionPagination {
124 limit: u64,
125 offset: u64,
126 }
127
128 impl SubscriptionPagination {
129 pub fn new(limit: u64, offset: u64) -> Self {
131 Self { limit, offset }
132 }
133 }
134
135 #[derive(Clone, Debug, Default, PartialEq, Eq)]
136 pub struct Subscriptions {
138 include_deleted: Option<bool>,
139 bill_day_of_month: Option<BillDayOfMonth>,
140 owner_id: Option<OwnerId>,
141 pagination: Option<SubscriptionPagination>,
142 location_id: Option<LocationId>,
143 package_id: Option<PackageId>,
144 }
145
146 impl Subscriptions {
147 pub fn builder() -> SubscriptionsBuilder {
149 SubscriptionsBuilder::default()
150 }
151 }
152
153 #[derive(Clone, Debug, Default)]
154 pub struct SubscriptionsBuilder {
156 include_deleted: Option<bool>,
157 bill_day_of_month: Option<BillDayOfMonth>,
158 owner_id: Option<OwnerId>,
159 pagination: Option<SubscriptionPagination>,
160 location_id: Option<LocationId>,
161 package_id: Option<PackageId>,
162 }
163
164 impl SubscriptionsBuilder {
165 pub fn include_deleted(mut self, include_deleted: bool) -> Self {
167 self.include_deleted = Some(include_deleted);
168 self
169 }
170
171 pub fn bill_day_of_month(mut self, bill_day_of_month: BillDayOfMonth) -> Self {
173 self.bill_day_of_month = Some(bill_day_of_month);
174 self
175 }
176
177 pub fn owner_id(mut self, owner_id: OwnerId) -> Self {
179 self.owner_id = Some(owner_id);
180 self
181 }
182
183 pub fn pagination(mut self, pagination: SubscriptionPagination) -> Self {
185 self.pagination = Some(pagination);
186 self
187 }
188
189 pub fn location_id(mut self, location_id: LocationId) -> Self {
191 self.location_id = Some(location_id);
192 self
193 }
194
195 pub fn package_id(mut self, package_id: PackageId) -> Self {
197 self.package_id = Some(package_id);
198 self
199 }
200
201 pub fn build(self) -> Subscriptions {
203 Subscriptions {
204 include_deleted: self.include_deleted,
205 bill_day_of_month: self.bill_day_of_month,
206 owner_id: self.owner_id,
207 pagination: self.pagination,
208 location_id: self.location_id,
209 package_id: self.package_id,
210 }
211 }
212 }
213
214 impl Request for Subscriptions {
215 fn method(&self) -> Method {
216 Method::Get
217 }
218
219 fn path(&self) -> &'static str {
220 "/api/v1/get_subscriptions"
221 }
222
223 fn parameters(&self) -> Vec<(String, String)> {
224 let mut params = Vec::new();
225 push_optional(&mut params, "include_deleted", self.include_deleted);
226 push_optional(&mut params, "bill_day_of_month", self.bill_day_of_month);
227 push_optional(&mut params, "owner_id", self.owner_id);
228 if let Some(pagination) = self.pagination {
229 params.push(("limit".to_owned(), pagination.limit.to_string()));
230 params.push(("offset".to_owned(), pagination.offset.to_string()));
231 }
232 push_optional(&mut params, "location_id", self.location_id);
233 push_optional(&mut params, "package_id", self.package_id);
234 params
235 }
236 }
237}
238
239pub mod list {
241 use super::*;
242
243 #[derive(Clone, Debug, PartialEq, Eq)]
244 pub struct Transactions {
246 from_date: Date,
247 to_date: Date,
248 }
249
250 impl Transactions {
251 pub fn builder() -> TransactionsBuilder {
253 TransactionsBuilder::default()
254 }
255 }
256
257 #[derive(Clone, Debug, Default)]
258 pub struct TransactionsBuilder {
260 from_date: Option<Date>,
261 to_date: Option<Date>,
262 }
263
264 impl TransactionsBuilder {
265 pub fn from_date(mut self, from_date: Date) -> Self {
267 self.from_date = Some(from_date);
268 self
269 }
270
271 pub fn to_date(mut self, to_date: Date) -> Self {
273 self.to_date = Some(to_date);
274 self
275 }
276
277 pub fn build(self) -> Result<Transactions> {
279 let from_date = self.from_date.ok_or(Error::MissingRequiredParameter {
280 parameter: "from_date",
281 })?;
282 let to_date = self.to_date.ok_or(Error::MissingRequiredParameter {
283 parameter: "to_date",
284 })?;
285 let cutover = cutover_date();
286 if from_date >= cutover {
287 return Err(Error::LegacyDateBoundary {
288 date: from_date.to_string(),
289 boundary: "list_transactions only returns POS transactions before 2019-08-01",
290 });
291 }
292 if to_date >= cutover {
293 return Err(Error::LegacyDateBoundary {
294 date: to_date.to_string(),
295 boundary: "list_transactions only returns POS transactions before 2019-08-01",
296 });
297 }
298 Ok(Transactions { from_date, to_date })
299 }
300 }
301
302 impl Request for Transactions {
303 fn method(&self) -> Method {
304 Method::Get
305 }
306
307 fn path(&self) -> &'static str {
308 "/api/v1/list_transactions"
309 }
310
311 fn parameters(&self) -> Vec<(String, String)> {
312 vec![
313 ("from_date".to_owned(), self.from_date.to_string()),
314 ("to_date".to_owned(), self.to_date.to_string()),
315 ]
316 }
317 }
318
319 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
320 pub struct InvoicePagination {
322 per_page: u64,
323 page: u64,
324 }
325
326 impl InvoicePagination {
327 pub fn new(per_page: u64, page: u64) -> Result<Self> {
329 if per_page == 0 {
330 return Err(Error::InvalidPagination {
331 reason: "list_invoices per_page must be greater than zero",
332 });
333 }
334 if page == 0 || !(page - 1).is_multiple_of(per_page) {
335 return Err(Error::InvalidPagination {
336 reason: "list_invoices page is a one-based starting result number incremented by per_page",
337 });
338 }
339 Ok(Self { per_page, page })
340 }
341 }
342
343 #[derive(Clone, Debug, Default, PartialEq, Eq)]
344 pub struct Invoices {
346 pagination: Option<InvoicePagination>,
347 complete: Option<bool>,
348 closed_only: Option<bool>,
349 from_date: Option<Date>,
350 to_date: Option<Date>,
351 }
352
353 impl Invoices {
354 pub fn builder() -> InvoicesBuilder {
356 InvoicesBuilder::default()
357 }
358 }
359
360 #[derive(Clone, Debug, Default)]
361 pub struct InvoicesBuilder {
363 pagination: Option<InvoicePagination>,
364 complete: Option<bool>,
365 closed_only: Option<bool>,
366 from_date: Option<Date>,
367 to_date: Option<Date>,
368 }
369
370 impl InvoicesBuilder {
371 pub fn pagination(mut self, pagination: InvoicePagination) -> Self {
373 self.pagination = Some(pagination);
374 self
375 }
376
377 pub fn complete(mut self, complete: bool) -> Self {
379 self.complete = Some(complete);
380 self
381 }
382
383 pub fn closed_only(mut self, closed_only: bool) -> Self {
385 self.closed_only = Some(closed_only);
386 self
387 }
388
389 pub fn from_date(mut self, from_date: Date) -> Self {
391 self.from_date = Some(from_date);
392 self
393 }
394
395 pub fn to_date(mut self, to_date: Date) -> Self {
397 self.to_date = Some(to_date);
398 self
399 }
400
401 pub fn build(self) -> Result<Invoices> {
403 let cutover = cutover_date();
404 for date in [&self.from_date, &self.to_date].into_iter().flatten() {
405 if date < &cutover {
406 return Err(Error::LegacyDateBoundary {
407 date: date.to_string(),
408 boundary: "list_invoices only returns invoices created on or after 2019-08-01",
409 });
410 }
411 }
412 Ok(Invoices {
413 pagination: self.pagination,
414 complete: self.complete,
415 closed_only: self.closed_only,
416 from_date: self.from_date,
417 to_date: self.to_date,
418 })
419 }
420 }
421
422 impl Request for Invoices {
423 fn method(&self) -> Method {
424 Method::Get
425 }
426
427 fn path(&self) -> &'static str {
428 "/api/v1/list_invoices"
429 }
430
431 fn parameters(&self) -> Vec<(String, String)> {
432 let mut params = Vec::new();
433 if let Some(pagination) = self.pagination {
434 params.push(("per_page".to_owned(), pagination.per_page.to_string()));
435 params.push(("page".to_owned(), pagination.page.to_string()));
436 }
437 push_optional(&mut params, "complete", self.complete);
438 push_optional(&mut params, "closed_only", self.closed_only);
439 push_optional(&mut params, "from_date", self.from_date);
440 push_optional(&mut params, "to_date", self.to_date);
441 params
442 }
443 }
444}
445
446#[derive(Clone, Copy, Debug, PartialEq, Eq)]
447pub struct TransactionId(u64);
449
450impl TransactionId {
451 pub fn new(value: u64) -> Self {
453 Self(value)
454 }
455}
456
457impl core::fmt::Display for TransactionId {
458 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
459 write!(formatter, "{}", self.0)
460 }
461}
462
463#[derive(Clone, Copy, Debug, PartialEq, Eq)]
464pub enum ResponseSensitivity {
466 PaymentSensitive,
468}
469
470#[derive(Clone, Debug, PartialEq, Eq)]
471pub struct Transaction {
473 id: TransactionId,
474}
475
476impl Transaction {
477 pub fn new(id: TransactionId) -> Self {
479 Self { id }
480 }
481
482 pub fn sensitivity(&self) -> ResponseSensitivity {
484 ResponseSensitivity::PaymentSensitive
485 }
486}
487
488impl Request for Transaction {
489 fn method(&self) -> Method {
490 Method::Post
491 }
492
493 fn path(&self) -> &'static str {
494 "/api/v1/transaction"
495 }
496
497 fn parameters(&self) -> Vec<(String, String)> {
498 vec![("id".to_owned(), self.id.to_string())]
499 }
500}