tgbot/types/payment/shipping/
mod.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    api::{Method, Payload},
5    types::{LabeledPrice, User},
6};
7
8#[cfg(test)]
9mod tests;
10
11/// Represents a shipping address.
12#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
13pub struct ShippingAddress {
14    /// City.
15    pub city: String,
16    /// ISO 3166-1 alpha-2 country code.
17    pub country_code: String,
18    /// Address post code.
19    pub post_code: String,
20    /// State, if applicable.
21    pub state: String,
22    /// First line for the address.
23    pub street_line1: String,
24    /// Second line for the address.
25    pub street_line2: String,
26}
27
28impl ShippingAddress {
29    /// Creates a new `ShippingAddress`.
30    ///
31    /// # Arguments
32    ///
33    /// * `city` - City.
34    /// * `country_code` - ISO 3166-1 alpha-2 country code.
35    /// * `post_code` - Post code.
36    /// * `state` - State.
37    /// * `street_line1` - First line for the address.
38    /// * `street_line2` - Second line for the address.
39    pub fn new<A, B, C, D, E, F>(
40        city: A,
41        country_code: B,
42        post_code: C,
43        state: D,
44        street_line1: E,
45        street_line2: F,
46    ) -> Self
47    where
48        A: Into<String>,
49        B: Into<String>,
50        C: Into<String>,
51        D: Into<String>,
52        E: Into<String>,
53        F: Into<String>,
54    {
55        Self {
56            city: city.into(),
57            country_code: country_code.into(),
58            post_code: post_code.into(),
59            state: state.into(),
60            street_line1: street_line1.into(),
61            street_line2: street_line2.into(),
62        }
63    }
64}
65
66/// Represents a shipping option.
67#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
68pub struct ShippingOption {
69    id: String,
70    title: String,
71    prices: Vec<LabeledPrice>,
72}
73
74impl ShippingOption {
75    /// Creates a new `ShippingOption`.
76    ///
77    /// # Arguments
78    ///
79    /// * `id` - Shipping option identifier.
80    /// * `title` - Option title.
81    /// * `prices` - List of price portions.
82    pub fn new<A, B, C>(id: A, title: B, prices: C) -> Self
83    where
84        A: Into<String>,
85        B: Into<String>,
86        C: IntoIterator<Item = LabeledPrice>,
87    {
88        Self {
89            id: id.into(),
90            title: title.into(),
91            prices: prices.into_iter().collect(),
92        }
93    }
94
95    /// Returns the ID of the option.
96    pub fn id(&self) -> &str {
97        &self.id
98    }
99
100    /// Returns the title of the option.
101    pub fn title(&self) -> &str {
102        &self.title
103    }
104
105    /// Returns the list of price portions.
106    pub fn prices(&self) -> &[LabeledPrice] {
107        &self.prices
108    }
109}
110
111/// Represents a shipping query.
112#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
113pub struct ShippingQuery {
114    /// Unique query identifier.
115    pub id: String,
116    /// User who sent the query.
117    pub from: User,
118    /// Bot specified invoice payload.
119    pub invoice_payload: String,
120    /// User specified shipping address.
121    pub shipping_address: ShippingAddress,
122}
123
124impl ShippingQuery {
125    /// Creates a new `ShippingQuery`.
126    ///
127    /// # Arguments
128    ///
129    /// * `id` - Query ID.
130    /// * `from` - Query sender.
131    /// * `invoice_payload` - Bot specified payload.
132    /// * `shipping_address` - User specified address.
133    pub fn new<A, B>(id: A, from: User, invoice_payload: B, shipping_address: ShippingAddress) -> Self
134    where
135        A: Into<String>,
136        B: Into<String>,
137    {
138        Self {
139            id: id.into(),
140            from,
141            invoice_payload: invoice_payload.into(),
142            shipping_address,
143        }
144    }
145}
146
147/// Replies to a shipping query.
148///
149/// If you sent an invoice requesting a shipping address
150/// and the parameter `is_flexible` was specified,
151/// the Bot API will send an [`crate::types::UpdateType::ShippingQuery`] to the bot.
152#[serde_with::skip_serializing_none]
153#[derive(Clone, Debug, Serialize)]
154pub struct AnswerShippingQuery {
155    ok: bool,
156    shipping_query_id: String,
157    error_message: Option<String>,
158    shipping_options: Option<Vec<ShippingOption>>,
159}
160
161impl AnswerShippingQuery {
162    /// Creates a new `AnswerShippingQuery` with a success answer.
163    ///
164    /// # Arguments
165    ///
166    /// * `id` - Unique identifier of the query to be answered.
167    /// * `options` - Array of available shipping options.
168    pub fn ok<A, B>(id: A, options: B) -> Self
169    where
170        A: Into<String>,
171        B: IntoIterator<Item = ShippingOption>,
172    {
173        Self {
174            ok: true,
175            shipping_query_id: id.into(),
176            error_message: None,
177            shipping_options: Some(options.into_iter().collect()),
178        }
179    }
180
181    /// Creates a new `AnswerShippingQuery` with an error answer.
182    ///
183    /// # Arguments
184    ///
185    /// * `id` - Unique identifier of the query to be answered.
186    /// * `message` - Error message in human readable form.
187    pub fn error<A, B>(id: A, message: B) -> Self
188    where
189        A: Into<String>,
190        B: Into<String>,
191    {
192        Self {
193            ok: false,
194            shipping_query_id: id.into(),
195            error_message: Some(message.into()),
196            shipping_options: None,
197        }
198    }
199}
200
201impl Method for AnswerShippingQuery {
202    type Response = bool;
203
204    fn into_payload(self) -> Payload {
205        Payload::json("answerShippingQuery", self)
206    }
207}