Change errors

This commit is contained in:
eraden 2022-04-26 20:03:42 +02:00
parent 9aeb78d64e
commit 4886a76a76
2 changed files with 138 additions and 96 deletions

View File

@ -96,7 +96,7 @@ impl From<Product> for pay_u::Product {
}
#[derive(Debug, actix::Message)]
#[rtype(result = "Result<PaymentResult>")]
#[rtype(result = "Result<pay_u::OrderId>")]
pub struct RequestPayment {
pub products: Vec<Product>,
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<pay_u::OrderId> {
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)

View File

@ -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<String>,
code: Option<String>,
severity: Option<String>,
code_literal: Option<CodeLiteral>,
},
#[error("PayU rejected to perform refund. {status_code:?}")]
RefundFailed {
status_code: String,
status_desc: Option<String>,
code: Option<String>,
severity: Option<String>,
code_literal: Option<CodeLiteral>,
},
}
pub type Result<T> = std::result::Result<T, Error>;
/// 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<String>,
}
@ -569,6 +588,73 @@ pub mod result {
pub refund: Option<Refund>,
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<Transaction>,
}
}
#[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<Transaction>,
}
}
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<result::CreateOrder> {
pub async fn create_order(&mut self, order: OrderCreateRequest) -> Result<res::CreateOrder> {
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::PartialRefund> {
) -> Result<res::PartialRefund> {
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::<result::PartialRefund>(include_str!(
let res = serde_json::from_str::<res::PartialRefund>(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::<result::PartialRefund>(include_str!(
let res = serde_json::from_str::<res::PartialRefund>(include_str!(
"../tests/responses/rejection.json"
));
assert!(res.is_ok());
}
#[test]
fn check_custom_literal_json() {
let res = serde_json::from_str::<result::PartialRefund>(include_str!(
let res = serde_json::from_str::<res::PartialRefund>(include_str!(
"../tests/responses/custom_code_literal.json"
));
assert!(res.is_ok());