From bb698853615124632a00954e6bac6468a9241d78 Mon Sep 17 00:00:00 2001 From: eraden Date: Fri, 22 Apr 2022 23:10:37 +0200 Subject: [PATCH] Working create order --- Cargo.lock | 27 ---------- pay_u/Cargo.toml | 3 +- pay_u/src/lib.rs | 129 ++++++++++++++++++++--------------------------- 3 files changed, 55 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d99a021..719b063 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -815,12 +815,6 @@ dependencies = [ "phf_codegen", ] -[[package]] -name = "chunked_transfer" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" - [[package]] name = "cipher" version = "0.3.0" @@ -2149,7 +2143,6 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "ureq", ] [[package]] @@ -3503,26 +3496,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "ureq" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" -dependencies = [ - "base64", - "chunked_transfer", - "encoding_rs", - "flate2", - "log", - "once_cell", - "rustls 0.20.4", - "serde", - "serde_json", - "url", - "webpki 0.22.0", - "webpki-roots 0.22.3", -] - [[package]] name = "url" version = "2.2.2" diff --git a/pay_u/Cargo.toml b/pay_u/Cargo.toml index d8a4a2d..acfb3f8 100644 --- a/pay_u/Cargo.toml +++ b/pay_u/Cargo.toml @@ -4,8 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ureq = { version = "2.4.0", features = ["json", "serde_json", "charset", "tls", "rustls"] } -reqwest = { version = "0.11.10", features = ["default", "rustls", "rustls-tls", "json"] } +reqwest = { version = "0.11.10", features = ["default", "native-tls", "json"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = { version = "1.0.79" } diff --git a/pay_u/src/lib.rs b/pay_u/src/lib.rs index b1fc0e0..8c272b6 100644 --- a/pay_u/src/lib.rs +++ b/pay_u/src/lib.rs @@ -1,3 +1,4 @@ +use reqwest::redirect; use serde::{Deserialize, Serialize}; #[derive(Debug, thiserror::Error)] @@ -5,11 +6,11 @@ pub enum Error { #[error("Client is not authorized. No bearer token available")] NoToken, #[error("{0}")] - UReq(#[from] ureq::Error), - #[error("{0}")] Io(#[from] std::io::Error), #[error("Total value is not sum of products price")] IncorrectTotal, + #[error("{0}")] + Reqwest(#[from] reqwest::Error), } pub type Result = std::result::Result; @@ -214,7 +215,7 @@ pub struct CreateOrderResult { /// This should be connected to your own order pub order_id: String, /// This is YOUR_EXT_ORDER_ID - pub ext_order_id: String, + pub ext_order_id: Option, } pub mod notify { @@ -257,37 +258,43 @@ pub struct Client { } impl Client { - pub fn create_order(&self, order: Order) -> Result { - if order.total_amount - != order - .products - .iter() - .fold(0, |memo, p| memo + (p.unit_price * p.quantity as i32)) - { - return Err(Error::IncorrectTotal); - } - - let req = ureq::post(&format!("{}/orders", self.base_url())) - .set("Content-Type", "application/json") - .set( - "Authorization", - &self - .bearer - .as_ref() - .map(|s| format!("Bearer {s}")) - .ok_or(Error::NoToken)?, - ); - // eprintln!("req {:?}", req); - let res = req.send_json(order)?; - // eprintln!("res {:?}", res); - // let r = res.into_string(); - // let x = r.is_ok(); - // let s = r.expect("Not a string"); - // eprintln!("s {:}", s); - res.into_json::().map_err(Into::into) - } - - pub async fn create_order2(&self, order: Order) -> Result { + /// Create new order in PayU + /// + /// ### IMPORTANT: + /// Do not follow redirect for any reason. Location points to + /// payment page which is useless in this context + /// + /// ### IMPORTANT: + /// Do not use rustls. It'll freeze application! + /// + /// # Examples + /// + /// ```rust + /// # use pay_u::{Client, Order, Product, Buyer}; + /// async fn pay() { + /// let client = Client { + /// bearer: Some(String::from("d9a4536e-62ba-4f60-8017-6053211d3f47")), + /// sandbox: true, + /// }; + /// let res = client + /// .create_order(Order { + /// notify_url: Some(String::from("https://your.eshop.com/notify")), + /// customer_ip: "127.0.0.1".to_string(), + /// merchant_pos_id: "300746".to_string(), + /// description: "RTV market".to_string(), + /// currency_code: "PLN".to_string(), + /// total_amount: 21000, + /// buyer: Buyer::new("john.doe@example.com", "654111654", "John", "Doe", "pl"), + /// products: vec![ + /// Product::new("Wireless Mouse for Laptop", 15000, 1), + /// Product::new("HDMI cable", 6000, 1), + /// ], + /// order_create_date: None, + /// }) + /// .await; + /// } + /// ``` + pub async fn create_order(&self, order: Order) -> Result { if order.total_amount != order .products @@ -297,27 +304,24 @@ impl Client { return Err(Error::IncorrectTotal); } let client = reqwest::ClientBuilder::default() - .https_only(true) - .referer(true) - .use_rustls_tls() + .user_agent("curl/7.82.0") + .use_native_tls() + // Do not follow! + .redirect(redirect::Policy::none()) + .connection_verbose(true) .build() .expect("Failed to create client"); let bearer = self.bearer.as_ref().cloned().unwrap_or_default(); - eprintln!("bearer {bearer:?}"); - let res = client - .post(format!("{}/orders", self.base_url())) + let path = format!("{}/orders", self.base_url()); + client + .post(path) .bearer_auth(bearer) .json(&order) .send() + .await? + .json::() .await - .expect("Request failed"); - let res = res.text().await.unwrap(); - eprintln!("{:?}", res); - Ok(serde_json::from_str(&res).unwrap()) - // Ok(res - // .json::() - // .await - // .expect("Invalid response")) + .map_err(Into::into) } fn base_url(&self) -> &str { @@ -333,33 +337,8 @@ impl Client { mod tests { use super::*; - #[test] - fn create_order() { - dotenv::dotenv().ok(); - - let client = Client { - bearer: Some(String::from("d9a4536e-62ba-4f60-8017-6053211d3f47")), - sandbox: true, - }; - let res = client.create_order(Order { - notify_url: Some(String::from("https://your.eshop.com/notify")), - customer_ip: "127.0.0.1".to_string(), - merchant_pos_id: "300746".to_string(), - description: "RTV market".to_string(), - currency_code: "PLN".to_string(), - total_amount: 21000, - buyer: Buyer::new("john.doe@example.com", "654111654", "John", "Doe", "pl"), - products: vec![ - Product::new("Wireless Mouse for Laptop", 15000, 1), - Product::new("HDMI cable", 6000, 1), - ], - order_create_date: None, - }); - assert!(res.is_ok()); - } - #[tokio::test] - async fn create_order2() { + async fn create_order() { dotenv::dotenv().ok(); let client = Client { @@ -367,7 +346,7 @@ mod tests { sandbox: true, }; let res = client - .create_order2(Order { + .create_order(Order { notify_url: Some(String::from("https://your.eshop.com/notify")), customer_ip: "127.0.0.1".to_string(), merchant_pos_id: "300746".to_string(),