From 4886a76a761731e99d202364fb4a31c6b2cbffea Mon Sep 17 00:00:00 2001 From: eraden Date: Tue, 26 Apr 2022 20:03:42 +0200 Subject: [PATCH] Change errors --- api/src/actors/payment_manager.rs | 6 +- pay_u/src/lib.rs | 228 ++++++++++++++++++------------ 2 files changed, 138 insertions(+), 96 deletions(-) diff --git a/api/src/actors/payment_manager.rs b/api/src/actors/payment_manager.rs index ea8275c..edb7a28 100644 --- a/api/src/actors/payment_manager.rs +++ b/api/src/actors/payment_manager.rs @@ -96,7 +96,7 @@ impl From for pay_u::Product { } #[derive(Debug, actix::Message)] -#[rtype(result = "Result")] +#[rtype(result = "Result")] pub struct RequestPayment { pub products: Vec, pub redirect_uri: String, @@ -106,11 +106,13 @@ pub struct RequestPayment { pub customer_ip: String, } +pay_async_handler!(RequestPayment, request_payment, pay_u::OrderId); + pub(crate) async fn request_payment( msg: RequestPayment, client: PayUClient, ) -> Result { - let mut client = &mut *client.lock(); + let client = &mut *client.lock(); let order = client .create_order( OrderCreateRequest::new(msg.buyer.into(), msg.customer_ip, msg.currency) diff --git a/pay_u/src/lib.rs b/pay_u/src/lib.rs index c75be33..29423b4 100644 --- a/pay_u/src/lib.rs +++ b/pay_u/src/lib.rs @@ -1,7 +1,6 @@ mod deserialize; mod serialize; -use std::fmt::Display; use std::sync::Arc; use reqwest::redirect; @@ -40,19 +39,39 @@ pub enum Error { Refund, #[error("Create order returned invalid response")] CreateOrder, -<<<<<<< HEAD - #[error("Operation failed with {0:?}")] - OpFailed(Status), -======= #[error("Failed to fetch order transactions")] OrderTransactions, ->>>>>>> 3ec4b209cd6a2ebefb4419083f9379794784d11c + #[error("PayU rejected to create order. {status_code:?}")] + CreateFailed { + status_code: String, + status_desc: Option, + code: Option, + severity: Option, + code_literal: Option, + }, + #[error("PayU rejected to perform refund. {status_code:?}")] + RefundFailed { + status_code: String, + status_desc: Option, + code: Option, + severity: Option, + code_literal: Option, + }, } pub type Result = std::result::Result; /// PayU internal order id -#[derive(derive_more::Display, derive_more::From, derive_more::Deref)] +#[derive( + Debug, + Clone, + serde::Deserialize, + serde::Serialize, + derive_more::Display, + derive_more::From, + derive_more::Deref, +)] +#[serde(transparent)] pub struct OrderId(pub String); impl OrderId { @@ -546,8 +565,8 @@ impl Status { } } -pub mod result { - use crate::{Refund, Status}; +pub mod res { + use crate::{OrderId, Refund, Status}; #[derive(serde::Deserialize, Debug)] #[serde(rename_all = "camelCase")] @@ -557,7 +576,7 @@ pub mod result { /// Client should be redirected to this URI pub redirect_uri: String, /// This should be connected to your own order - pub order_id: String, + pub order_id: OrderId, /// This is YOUR_EXT_ORDER_ID pub ext_order_id: Option, } @@ -569,6 +588,73 @@ pub mod result { pub refund: Option, pub status: Status, } + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct TransactionPayMethod { + pub value: String, + } + + #[derive(serde::Deserialize)] + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] + pub enum CardProfile { + Consumer, + Business, + } + + #[derive(serde::Deserialize)] + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] + pub enum CardClassification { + Debit, + Credit, + } + + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct TransactionCartData { + /// // "543402******4014", + pub card_number_masked: String, + /// MC (MasterCard/Maestro), VS (Visa) + /// Example; "MC" + pub card_scheme: String, + pub card_profile: CardProfile, + pub card_classification: CardClassification, + /// Example: "000" + pub card_response_code: String, + /// Example: "000 - OK" + pub card_response_code_desc: String, + /// Example: "5" + pub card_eci_code: String, + /// Example: "AY", + pub card3ds_status: String, + /// Example: "PL", + pub card_bin_country: String, + /// Example: "MCC0111LL1121" + pub first_transaction_id: String, + } + + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct TransactionCardInstallmentProposal {} + + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct TransactionCart { + pub cart_data: TransactionCartData, + pub card_installment_proposal: TransactionCardInstallmentProposal, + } + + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct Transaction { + pub pay_method: TransactionPayMethod, + pub payment_flow: String, + } + + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct Transactions { + pub transactions: Vec, + } } #[derive(Deserialize, Serialize, Debug)] @@ -614,9 +700,8 @@ pub struct Refund { pub mod notify { use serde::Deserialize; - use crate::OrderId; - use super::deserialize; + use crate::OrderId; /// Payment notification object received on [super::Order].[notify_url] #[derive(Deserialize, Debug)] @@ -692,76 +777,6 @@ pub mod notify { } } -pub mod res { - #[derive(serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct TransactionPayMethod { - pub value: String, - } - - #[derive(serde::Deserialize)] - #[serde(rename_all = "SCREAMING_SNAKE_CASE")] - pub enum CardProfile { - Consumer, - Business, - } - - #[derive(serde::Deserialize)] - #[serde(rename_all = "SCREAMING_SNAKE_CASE")] - pub enum CardClassification { - Debit, - Credit, - } - - #[derive(serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct TransactionCartData { - /// // "543402******4014", - pub card_number_masked: String, - /// MC (MasterCard/Maestro), VS (Visa) - /// Example; "MC" - pub card_scheme: String, - pub card_profile: CardProfile, - pub card_classification: CardClassification, - /// Example: "000" - pub card_response_code: String, - /// Example: "000 - OK" - pub card_response_code_desc: String, - /// Example: "5" - pub card_eci_code: String, - /// Example: "AY", - pub card3ds_status: String, - /// Example: "PL", - pub card_bin_country: String, - /// Example: "MCC0111LL1121" - pub first_transaction_id: String, - } - - #[derive(serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct TransactionCardInstallmentProposal {} - - #[derive(serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct TransactionCart { - pub cart_data: TransactionCartData, - pub card_installment_proposal: TransactionCardInstallmentProposal, - } - - #[derive(serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct Transaction { - pub pay_method: TransactionPayMethod, - pub payment_flow: String, - } - - #[derive(serde::Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct Transactions { - pub transactions: Vec, - } -} - pub struct Client { sandbox: bool, merchant_pos_id: MerchantPosId, @@ -856,7 +871,7 @@ impl Client { /// .await; /// } /// ``` - pub async fn create_order(&mut self, order: OrderCreateRequest) -> Result { + pub async fn create_order(&mut self, order: OrderCreateRequest) -> Result { self.authorize().await?; if order.total_amount != order @@ -887,12 +902,25 @@ impl Client { .text() .await?; log::trace!("Response: {}", text); - let res: result::CreateOrder = serde_json::from_str(&text).map_err(|e| { + let res: res::CreateOrder = serde_json::from_str(&text).map_err(|e| { log::error!("{e:?}"); Error::CreateOrder })?; if res.status.status_code != "Success" { - return Err(Error::OpFailed(res.status)); + let Status { + status_code, + status_desc, + code, + severity, + code_literal, + } = res.status; + return Err(Error::CreateFailed { + status_desc, + status_code, + code, + severity, + code_literal, + }); } Ok(res) } @@ -927,7 +955,7 @@ impl Client { /// .sandbox(); /// let res = client /// .partial_refund( - /// "H9LL64F37H160126GUEST000P01", + /// OrderId::new("H9LL64F37H160126GUEST000P01"), /// RefundRequest::new("Refund", 1000), /// ) /// .await; @@ -937,7 +965,7 @@ impl Client { &mut self, order_id: OrderId, refund: RefundRequest, - ) -> Result { + ) -> Result { self.authorize().await?; if refund.description().trim().is_empty() { return Err(Error::NoDescription); @@ -955,12 +983,25 @@ impl Client { .text() .await?; log::trace!("Response: {}", text); - let res: result::PartialRefund = serde_json::from_str(&text).map_err(|e| { + let res: res::PartialRefund = serde_json::from_str(&text).map_err(|e| { log::error!("Invalid PayU response {e:?}"); Error::Refund })?; if res.status.status_code.as_str() != "Success" { - return Err(Error::OpFailed(res.status)); + let Status { + status_code, + status_desc, + code, + severity, + code_literal, + } = res.status; + return Err(Error::RefundFailed { + status_desc, + status_code, + code, + severity, + code_literal, + }); } Ok(res) } @@ -984,7 +1025,7 @@ impl Client { /// .with_bearer("d9a4536e-62ba-4f60-8017-6053211d3f47", 2000) /// .sandbox(); /// let res = client - /// .order_transactions("H9LL64F37H160126GUEST000P01") + /// .order_transactions(OrderId::new("H9LL64F37H160126GUEST000P01")) /// .await; /// } /// ``` @@ -1099,7 +1140,6 @@ mod tests { RefundRequest::new("Refund", 1000), ) .await; - eprintln!("{:?}", res); assert!(matches!(res, Ok(_))); } @@ -1108,7 +1148,7 @@ mod tests { #[test] fn check_accepted_refund_json() { - let res = serde_json::from_str::(include_str!( + let res = serde_json::from_str::(include_str!( "../tests/responses/accepted_refund.json" )); assert!(res.is_ok()); @@ -1150,14 +1190,14 @@ mod tests { } #[test] fn check_rejection_json() { - let res = serde_json::from_str::(include_str!( + let res = serde_json::from_str::(include_str!( "../tests/responses/rejection.json" )); assert!(res.is_ok()); } #[test] fn check_custom_literal_json() { - let res = serde_json::from_str::(include_str!( + let res = serde_json::from_str::(include_str!( "../tests/responses/custom_code_literal.json" )); assert!(res.is_ok());