some fixes

This commit is contained in:
Edgar 2022-05-12 09:58:36 +02:00
parent 89b1fdf113
commit a4c4838aaf
No known key found for this signature in database
GPG key ID: 8731E6C0166EAA85
11 changed files with 66 additions and 54 deletions

View file

@ -4,7 +4,7 @@
//! Customers with a PayPal account can log in and pay the invoice with PayPal. Alternatively,
//! customers can pay as a guest with a debit card or credit card. For more information, see the Invoicing Overview and the Invoicing Integration Guide.
//!
//! Reference: https://developer.paypal.com/docs/api/invoicing/v2/
//! Reference: <https://developer.paypal.com/docs/api/invoicing/v2/>
use std::borrow::Cow;
@ -53,8 +53,8 @@ impl Endpoint for GenerateInvoiceNumber {
reqwest::Method::POST
}
fn body(&self) -> Option<&Self::Body> {
Some(&self.invoice_number)
fn body(&self) -> Option<Self::Body> {
Some(self.invoice_number.clone())
}
}
@ -88,8 +88,8 @@ impl Endpoint for CreateDraftInvoice {
reqwest::Method::POST
}
fn body(&self) -> Option<&Self::Body> {
Some(&self.invoice)
fn body(&self) -> Option<Self::Body> {
Some(self.invoice.clone())
}
}
@ -153,8 +153,8 @@ impl Endpoint for ListInvoices {
reqwest::Method::GET
}
fn query(&self) -> Option<&Self::Query> {
Some(&self.query)
fn query(&self) -> Option<Self::Query> {
Some(self.query.clone())
}
}
@ -234,12 +234,12 @@ impl Endpoint for UpdateInvoice {
reqwest::Method::PUT
}
fn body(&self) -> Option<&Self::Body> {
Some(&self.invoice)
fn body(&self) -> Option<Self::Body> {
Some(self.invoice.clone())
}
fn query(&self) -> Option<&Self::Query> {
Some(&self.query)
fn query(&self) -> Option<Self::Query> {
Some(self.query.clone())
}
}
@ -274,8 +274,8 @@ impl Endpoint for CancelInvoice {
reqwest::Method::POST
}
fn body(&self) -> Option<&Self::Body> {
Some(&self.reason)
fn body(&self) -> Option<Self::Body> {
Some(self.reason.clone())
}
}
@ -383,7 +383,7 @@ mod tests {
let invoice = CreateDraftInvoice::new(payload);
let res = client.execute(&invoice).await?;
let _res = client.execute(&invoice).await?;
Ok(())
}
}

View file

@ -2,4 +2,4 @@
pub mod invoice;
pub mod orders;
pub mod payments;
pub mod payments;

View file

@ -1,6 +1,6 @@
//! An order represents a payment between two or more parties. Use the Orders API to create, update, retrieve, authorize, and capture orders.
//!
//! https://developer.paypal.com/docs/api/orders/v2/
//! <https://developer.paypal.com/docs/api/orders/v2/>
use std::borrow::Cow;
@ -41,8 +41,8 @@ impl Endpoint for CreateOrder {
reqwest::Method::POST
}
fn body(&self) -> Option<&Self::Body> {
Some(&self.order)
fn body(&self) -> Option<Self::Body> {
Some(self.order.clone())
}
}
@ -97,10 +97,11 @@ pub struct PaymentSource {
}
/// The capture order endpoint body.
#[derive(Debug, Serialize, Clone)]
#[derive(Debug, Serialize, Clone, Default)]
pub struct PaymentSourceBody {
/// The payment source definition.
pub payment_source: PaymentSource,
#[serde(skip_serializing_if = "Option::is_none")]
pub payment_source: Option<PaymentSource>,
}
/// Captures payment for an order. To successfully capture payment for an order,
@ -111,7 +112,7 @@ pub struct CaptureOrder {
/// The id of the order.
pub order_id: String,
/// The endpoint body.
pub body: Option<PaymentSourceBody>,
pub body: PaymentSourceBody,
}
impl CaptureOrder {
@ -119,7 +120,7 @@ impl CaptureOrder {
pub fn new(order_id: &str) -> Self {
Self {
order_id: order_id.to_string(),
body: None,
body: PaymentSourceBody::default(),
}
}
}
@ -139,8 +140,8 @@ impl Endpoint for CaptureOrder {
reqwest::Method::POST
}
fn body(&self) -> Option<&Self::Body> {
self.body.as_ref()
fn body(&self) -> Option<Self::Body> {
Some(self.body.clone())
}
}
@ -152,7 +153,7 @@ pub struct AuthorizeOrder {
/// The order id.
order_id: String,
/// The endpoint body.
pub body: Option<PaymentSourceBody>,
pub body: PaymentSourceBody,
}
impl AuthorizeOrder {
@ -160,7 +161,7 @@ impl AuthorizeOrder {
pub fn new(order_id: &str) -> Self {
Self {
order_id: order_id.to_string(),
body: None,
body: PaymentSourceBody::default(),
}
}
}
@ -180,8 +181,8 @@ impl Endpoint for AuthorizeOrder {
reqwest::Method::POST
}
fn body(&self) -> Option<&Self::Body> {
self.body.as_ref()
fn body(&self) -> Option<Self::Body> {
Some(self.body.clone())
}
}
@ -194,7 +195,7 @@ mod tests {
#[tokio::test]
async fn test_order() -> anyhow::Result<()> {
let mut client = create_client().await;
client.get_access_token().await?;
client.get_access_token().await.expect("get access token error");
let order = OrderPayloadBuilder::default()
.intent(Intent::Authorize)
@ -219,7 +220,11 @@ mod tests {
..Default::default()
},
)
.await?;
.await;
assert!(order_created.is_ok());
let order_created = order_created?;
assert_ne!(order_created.id, "");
assert_eq!(order_created.status, OrderStatus::Created);
@ -235,14 +240,19 @@ mod tests {
..Default::default()
},
)
.await?;
.await;
assert!(show_order_result.is_ok());
let show_order_result = show_order_result?;
assert_eq!(order_created.id, show_order_result.id);
assert_eq!(order_created.status, show_order_result.status);
let capture_order = CaptureOrder::new(&show_order_result.id);
let authorize_order = AuthorizeOrder::new(&show_order_result.id);
let _res = client.execute(&capture_order).await?;
let res = client.execute(&authorize_order).await;
assert!(res.is_err()); // Fails with ORDER_NOT_APPROVED
Ok(())
}

View file

@ -1,6 +1,6 @@
//! Call the Payments API to authorize payments, capture authorized payments, refund payments that have already been captured, and show payment information.
//!
//! Reference: https://developer.paypal.com/docs/api/payments/v2/
//! Reference: <https://developer.paypal.com/docs/api/payments/v2/>
use std::borrow::Cow;
@ -42,8 +42,4 @@ impl Endpoint for GetAuthorizedPayment {
fn method(&self) -> reqwest::Method {
reqwest::Method::GET
}
fn body(&self) -> Option<&Self::Body> {
None
}
}

View file

@ -13,7 +13,7 @@ use crate::{
/// Represents the access token returned by the OAuth2 authentication.
///
/// https://developer.paypal.com/docs/api/get-an-access-token-postman/
/// <https://developer.paypal.com/docs/api/get-an-access-token-postman/>
#[derive(Debug, Deserialize)]
pub struct AccessToken {
/// The OAuth2 scopes.
@ -196,7 +196,7 @@ impl Client {
let mut url = endpoint.full_path(self.sandbox);
if let Some(query) = endpoint.query() {
let query_string = serde_qs::to_string(query).expect("serialize the query correctly");
let query_string = serde_qs::to_string(&query).expect("serialize the query correctly");
url.push_str(&query_string);
}
@ -204,7 +204,7 @@ impl Client {
request = self.setup_headers(request, headers).await?;
if let Some(body) = endpoint.body() {
request = request.json(body);
request = request.json(&body);
}
let res = request.send().await?;
@ -225,7 +225,7 @@ impl Client {
/// Executes the given endpoints with the default headers.
///
/// You must remember to call `get_access_token` first or this may fail due to not being authed.
/// You must remember to call [Client::get_access_token] first or this may fail due to not being authed.
pub async fn execute<E>(&self, endpoint: &E) -> Result<E::Response, ResponseError>
where
E: Endpoint,

View file

@ -1,4 +1,4 @@
//! Generated using https://github.com/edg-l/payhelper
//! Generated using <https://github.com/edg-l/payhelper>
use crate::errors::InvalidCountryError;
use serde::{Deserialize, Serialize};

View file

@ -8,7 +8,7 @@ use std::str::FromStr;
/// The phone type.
///
/// https://developer.paypal.com/docs/api/orders/v2/#definition-phone_with_type
/// <https://developer.paypal.com/docs/api/orders/v2/#definition-phone_with_type>
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[allow(missing_docs)]

View file

@ -569,7 +569,7 @@ pub struct InvoicePayload {
pub refunds: Option<Refunds>,
}
/// Definition: https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get
/// Definition: <https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get>
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into))]

View file

@ -27,7 +27,7 @@ impl Default for Intent {
/// Represents a payer name.
///
/// https://developer.paypal.com/docs/api/orders/v2/#definition-payer.name
/// <https://developer.paypal.com/docs/api/orders/v2/#definition-payer.name>
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct PayerName {
/// When the party is a person, the party's given, or first, name.
@ -80,7 +80,7 @@ pub struct TaxInfo {
/// The customer who approves and pays for the order. The customer is also known as the payer.
///
/// https://developer.paypal.com/docs/api/orders/v2/#definition-payer
/// <https://developer.paypal.com/docs/api/orders/v2/#definition-payer>
#[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
pub struct Payer {
@ -428,7 +428,7 @@ pub struct PurchaseUnit {
pub id: Option<String>,
/// The soft descriptor is the dynamic text used to construct the statement descriptor that appears on a payer's card statement.
///
/// More info here: https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request
/// More info here: <https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request>
pub soft_descriptor: Option<String>,
/// An array of items that the customer purchases from the merchant.
pub items: Option<Vec<Item>>,

View file

@ -20,12 +20,12 @@ pub trait Endpoint {
fn method(&self) -> reqwest::Method;
/// The query to be used when calling this endpoint.
fn query(&self) -> Option<&Self::Query> {
fn query(&self) -> Option<Self::Query> {
None
}
/// The body to be used when calling this endpoint.
fn body(&self) -> Option<&Self::Body> {
fn body(&self) -> Option<Self::Body> {
None
}
@ -33,10 +33,14 @@ pub trait Endpoint {
///
/// Automatically implemented.
fn full_path(&self, is_sandbox: bool) -> String {
let relative_path = self.relative_path();
assert!(relative_path.starts_with('/'), "relative path must start with '/'");
if is_sandbox {
format!("{}{}", SANDBOX_ENDPOINT, self.relative_path())
format!("{}{}", SANDBOX_ENDPOINT, relative_path)
} else {
format!("{}{}", LIVE_ENDPOINT, self.relative_path())
format!("{}{}", LIVE_ENDPOINT, relative_path)
}
}
}

View file

@ -6,6 +6,8 @@
//! [![Docs](https://docs.rs/paypal-rs/badge.svg)](https://docs.rs/paypal-rs)
//!
//! A rust library that wraps the [paypal api](https://developer.paypal.com/docs/api) asynchronously in a strongly typed manner.
//!
//! If there is a missing endpoint that you need, you may try to implement the [Endpoint](endpoint::Endpoint) and pass it to [Client::execute](client::Client::execute)
//!
//! Currently in early development.
//!
@ -91,7 +93,7 @@ pub const LIVE_ENDPOINT: &str = "https://api-m.paypal.com";
pub const SANDBOX_ENDPOINT: &str = "https://api-m.sandbox.paypal.com";
/// Represents the query used in most GET api requests.
///
/// Reference: https://developer.paypal.com/docs/api/reference/api-requests/#query-parameters
/// Reference: <https://developer.paypal.com/docs/api/reference/api-requests/#query-parameters>
///
/// Note: You can avoid most fields by the Default impl like so:
/// ```
@ -130,7 +132,7 @@ pub struct Query {
/// Represents the optional header values used on paypal requests.
///
/// https://developer.paypal.com/docs/api/reference/api-requests/#paypal-auth-assertion
/// <https://developer.paypal.com/docs/api/reference/api-requests/#paypal-auth-assertion>
#[derive(Debug, Default, Builder, Clone)]
pub struct HeaderParams {
/// The merchant payer id used on PayPal-Auth-Assertion