use crate::types::{primitive::Integer, user::User};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize)]
pub struct Invoice {
pub title: String,
pub description: String,
pub start_parameter: String,
pub currency: String,
pub total_amount: Integer,
}
#[derive(Clone, Debug, Serialize)]
pub struct LabeledPrice {
label: String,
amount: Integer,
}
impl LabeledPrice {
pub fn new<S: Into<String>>(label: S, amount: Integer) -> Self {
Self {
label: label.into(),
amount,
}
}
pub fn label(&self) -> &str {
&self.label
}
pub fn amount(&self) -> Integer {
self.amount
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct OrderInfo {
pub name: Option<String>,
pub phone_number: Option<String>,
pub email: Option<String>,
pub shipping_address: Option<ShippingAddress>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct PreCheckoutQuery {
pub id: String,
pub from: User,
pub currency: String,
pub total_amount: Integer,
pub invoice_payload: String,
pub shipping_option_id: Option<String>,
pub order_info: Option<OrderInfo>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct ShippingAddress {
pub country_code: String,
pub state: String,
pub city: String,
pub street_line1: String,
pub street_line2: String,
pub post_code: String,
}
#[derive(Clone, Debug, Serialize)]
pub struct ShippingOption {
id: String,
title: String,
prices: Vec<LabeledPrice>,
}
impl ShippingOption {
pub fn new<I, T>(id: I, title: T, prices: Vec<LabeledPrice>) -> Self
where
I: Into<String>,
T: Into<String>,
{
Self {
id: id.into(),
title: title.into(),
prices,
}
}
pub fn id(&self) -> &str {
&self.id
}
pub fn title(&self) -> &str {
&self.title
}
pub fn prices(&self) -> &[LabeledPrice] {
&self.prices
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct ShippingQuery {
pub id: String,
pub from: User,
pub invoice_payload: String,
pub shipping_address: ShippingAddress,
}
#[derive(Clone, Debug, Deserialize)]
pub struct SuccessfulPayment {
pub currency: String,
pub total_amount: Integer,
pub invoice_payload: String,
pub shipping_option_id: Option<String>,
pub order_info: Option<OrderInfo>,
pub telegram_payment_charge_id: String,
pub provider_payment_charge_id: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize_invoice() {
let data: Invoice = serde_json::from_value(serde_json::json!({
"title": "invoice title",
"description": "invoice description",
"start_parameter": "invoice start parameter",
"currency": "RUB",
"total_amount": 100
}))
.unwrap();
assert_eq!(data.title, "invoice title");
assert_eq!(data.description, "invoice description");
assert_eq!(data.start_parameter, "invoice start parameter");
assert_eq!(data.currency, "RUB");
assert_eq!(data.total_amount, 100);
}
#[test]
fn serialize_labeled_price() {
let price = LabeledPrice::new("price label", 145);
let data = serde_json::to_string(&price).unwrap();
let new_price: serde_json::Value = serde_json::from_str(&data).unwrap();
assert_eq!(price.label(), new_price.get("label").unwrap().as_str().unwrap());
assert_eq!(price.amount(), new_price.get("amount").unwrap().as_i64().unwrap());
}
#[test]
fn deserialize_order_info_full() {
let data: OrderInfo = serde_json::from_value(serde_json::json!({
"name": "magticom",
"phone_number": "+995 32 217 00 00",
"email": "office@magticom.ge",
"shipping_address": {
"country_code": "GE",
"state": "",
"city": "Tbilisi",
"street_line1": "7 A. Politkovskaya st.",
"street_line2": "",
"post_code": ""
}
}))
.unwrap();
assert_eq!(data.name.unwrap(), "magticom");
assert_eq!(data.phone_number.unwrap(), "+995 32 217 00 00");
assert_eq!(data.email.unwrap(), "office@magticom.ge");
let addr = data.shipping_address.unwrap();
assert_eq!(addr.country_code, "GE");
assert_eq!(addr.state, "");
assert_eq!(addr.city, "Tbilisi");
assert_eq!(addr.street_line1, "7 A. Politkovskaya st.");
assert_eq!(addr.street_line2, "");
assert_eq!(addr.post_code, "");
}
#[test]
fn deserialize_order_info_partial() {
let data: OrderInfo = serde_json::from_value(serde_json::json!({})).unwrap();
assert!(data.name.is_none());
assert!(data.phone_number.is_none());
assert!(data.email.is_none());
assert!(data.shipping_address.is_none());
}
#[test]
fn deserialize_pre_checkout_query_full() {
let data: PreCheckoutQuery = serde_json::from_value(serde_json::json!({
"id": "query id",
"from": {
"id": 1,
"first_name": "test",
"is_bot": false
},
"currency": "GEL",
"total_amount": 100,
"invoice_payload": "invoice payload",
"shipping_option_id": "option id",
"order_info": {}
}))
.unwrap();
assert_eq!(data.id, "query id");
assert_eq!(data.from.id, 1);
assert_eq!(data.currency, "GEL");
assert_eq!(data.total_amount, 100);
assert_eq!(data.invoice_payload, "invoice payload");
assert_eq!(data.shipping_option_id.unwrap(), "option id");
assert!(data.order_info.unwrap().name.is_none());
}
#[test]
fn deserialize_pre_checkout_query_partial() {
let data: PreCheckoutQuery = serde_json::from_value(serde_json::json!({
"id": "query id",
"from": {
"id": 1,
"first_name": "test",
"is_bot": false
},
"currency": "GEL",
"total_amount": 100,
"invoice_payload": "invoice payload"
}))
.unwrap();
assert_eq!(data.id, "query id");
assert_eq!(data.from.id, 1);
assert_eq!(data.currency, "GEL");
assert_eq!(data.total_amount, 100);
assert_eq!(data.invoice_payload, "invoice payload");
assert!(data.shipping_option_id.is_none());
assert!(data.order_info.is_none());
}
#[test]
fn deserialize_shipping_address() {
let data: ShippingAddress = serde_json::from_value(serde_json::json!({
"country_code": "RU",
"state": "Chechen Republic",
"city": "Gudermes",
"street_line1": "Nuradilov st., 12",
"street_line2": "",
"post_code": "366200"
}))
.unwrap();
assert_eq!(data.country_code, "RU");
assert_eq!(data.state, "Chechen Republic");
assert_eq!(data.city, "Gudermes");
assert_eq!(data.street_line1, "Nuradilov st., 12");
assert_eq!(data.street_line2, "");
assert_eq!(data.post_code, "366200");
}
#[test]
fn serialize_shipping_option() {
let option = ShippingOption::new("id", "title", vec![]);
let data = serde_json::to_string(&option).unwrap();
let new_option: serde_json::Value = serde_json::from_str(&data).unwrap();
assert_eq!(new_option.get("id").unwrap().as_str().unwrap(), option.id());
assert_eq!(new_option.get("title").unwrap().as_str().unwrap(), option.title());
assert!(new_option.get("prices").unwrap().as_array().unwrap().is_empty());
assert!(option.prices().is_empty())
}
#[test]
fn deserialize_shipping_query() {
let data: ShippingQuery = serde_json::from_value(serde_json::json!({
"id": "query-id",
"from": {
"id": 1,
"first_name": "test",
"is_bot": false
},
"invoice_payload": "payload",
"shipping_address": {
"country_code": "RU",
"state": "Chechen Republic",
"city": "Gudermes",
"street_line1": "Nuradilov st., 12",
"street_line2": "",
"post_code": "366200"
}
}))
.unwrap();
assert_eq!(data.id, "query-id");
assert_eq!(data.from.id, 1);
assert_eq!(data.invoice_payload, "payload");
assert_eq!(data.shipping_address.country_code, "RU");
}
#[test]
fn deserialize_successful_payment_full() {
let data: SuccessfulPayment = serde_json::from_value(serde_json::json!({
"currency": "RUB",
"total_amount": 145,
"invoice_payload": "invoice payload",
"shipping_option_id": "option id",
"order_info": {},
"telegram_payment_charge_id": "tg-charge-id",
"provider_payment_charge_id": "provider-charge-id"
}))
.unwrap();
assert_eq!(data.currency, "RUB");
assert_eq!(data.total_amount, 145);
assert_eq!(data.invoice_payload, "invoice payload");
assert_eq!(data.shipping_option_id.unwrap(), "option id");
assert!(data.order_info.unwrap().name.is_none());
assert_eq!(data.telegram_payment_charge_id, "tg-charge-id");
assert_eq!(data.provider_payment_charge_id, "provider-charge-id");
}
#[test]
fn deserialize_successful_payment_partial() {
let data: SuccessfulPayment = serde_json::from_value(serde_json::json!({
"currency": "RUB",
"total_amount": 145,
"invoice_payload": "invoice payload",
"telegram_payment_charge_id": "tg-charge-id",
"provider_payment_charge_id": "provider-charge-id"
}))
.unwrap();
assert_eq!(data.currency, "RUB");
assert_eq!(data.total_amount, 145);
assert_eq!(data.invoice_payload, "invoice payload");
assert!(data.shipping_option_id.is_none());
assert!(data.order_info.is_none());
assert_eq!(data.telegram_payment_charge_id, "tg-charge-id");
assert_eq!(data.provider_payment_charge_id, "provider-charge-id");
}
}