progress with orders
This commit is contained in:
parent
32f5493c95
commit
b9845d284f
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "paypal-rs"
|
name = "paypal-rs"
|
||||||
version = "0.0.4"
|
version = "0.0.5"
|
||||||
authors = ["Edgar <git@edgarluque.com>"]
|
authors = ["Edgar <git@edgarluque.com>"]
|
||||||
description = "A library that wraps the paypal api asynchronously."
|
description = "A library that wraps the paypal api asynchronously."
|
||||||
repository = "https://github.com/edg-l/paypal-rs/"
|
repository = "https://github.com/edg-l/paypal-rs/"
|
||||||
|
@ -16,6 +16,7 @@ edition = "2018"
|
||||||
reqwest = { version = "0.10", features = ["json"] }
|
reqwest = { version = "0.10", features = ["json"] }
|
||||||
tokio = { version = "0.2", features = ["full"] }
|
tokio = { version = "0.2", features = ["full"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
jsonwebtoken = "7"
|
jsonwebtoken = "7"
|
||||||
base64 = "0.12"
|
base64 = "0.12"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
![Rust](https://github.com/edg-l/paypal-rs/workflows/Rust/badge.svg)
|
![Rust](https://github.com/edg-l/paypal-rs/workflows/Rust/badge.svg)
|
||||||
![Docs](https://docs.rs/paypal-rs/badge.svg)
|
![Docs](https://docs.rs/paypal-rs/badge.svg)
|
||||||
|
|
||||||
A rust library that wraps the [paypal api](https://developer.paypal.com/docs/api) asynchronously.
|
A rust library that wraps the [paypal api](https://developer.paypal.com/docs/api) asynchronously in a strongly typed manner.
|
||||||
|
|
||||||
Crate: https://crates.io/crates/paypal-rs
|
Crate: https://crates.io/crates/paypal-rs
|
||||||
|
|
||||||
|
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
max_width = 120
|
|
@ -5,5 +5,5 @@ pub enum Errors {
|
||||||
#[error("failed to get access token")]
|
#[error("failed to get access token")]
|
||||||
GetAccessTokenFailure,
|
GetAccessTokenFailure,
|
||||||
#[error("failure when calling the paypal api")]
|
#[error("failure when calling the paypal api")]
|
||||||
ApiCallFailure,
|
ApiCallFailure(String),
|
||||||
}
|
}
|
55
src/lib.rs
55
src/lib.rs
|
@ -6,10 +6,10 @@ extern crate chrono;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod orders;
|
pub mod orders;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
use reqwest::header::HeaderMap;
|
|
||||||
use reqwest::header;
|
use reqwest::header;
|
||||||
|
use reqwest::header::HeaderMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
pub const LIVE_ENDPOINT: &str = "https://api.paypal.com";
|
pub const LIVE_ENDPOINT: &str = "https://api.paypal.com";
|
||||||
pub const SANDBOX_ENDPOINT: &str = "https://api.sandbox.paypal.com";
|
pub const SANDBOX_ENDPOINT: &str = "https://api.sandbox.paypal.com";
|
||||||
|
@ -94,7 +94,7 @@ pub struct Query {
|
||||||
/// When results are paged, you can use the next_id value as the start_id to continue with the next set of results.
|
/// When results are paged, you can use the next_id value as the start_id to continue with the next set of results.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub start_id: Option<String>,
|
pub start_id: Option<String>,
|
||||||
/// The start index of the payments to list. Typically, you use the start_index to jump to a specific position in the resource history based on its cart.
|
/// The start index of the payments to list. Typically, you use the start_index to jump to a specific position in the resource history based on its cart.
|
||||||
/// For example, to start at the second item in a list of results, specify start_index=2.
|
/// For example, to start at the second item in a list of results, specify start_index=2.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub start_index: Option<i32>,
|
pub start_index: Option<i32>,
|
||||||
|
@ -104,7 +104,7 @@ pub struct Query {
|
||||||
// TODO: Use https://github.com/samscott89/serde_qs
|
// TODO: Use https://github.com/samscott89/serde_qs
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum Prefer {
|
pub enum Prefer {
|
||||||
/// The server returns a minimal response to optimize communication between the API caller and the server.
|
/// The server returns a minimal response to optimize communication between the API caller and the server.
|
||||||
/// A minimal response includes the id, status and HATEOAS links.
|
/// A minimal response includes the id, status and HATEOAS links.
|
||||||
|
@ -124,11 +124,21 @@ impl Default for Prefer {
|
||||||
/// 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)]
|
#[derive(Debug, Default)]
|
||||||
pub struct HeaderParams {
|
pub struct HeaderParams {
|
||||||
pub merchant_payer_id: Option<String>,
|
/// The merchant payer id used on PayPal-Auth-Assertion
|
||||||
|
pub merchant_payer_id: Option<String>,
|
||||||
|
/// Verifies that the payment originates from a valid, user-consented device and application.
|
||||||
|
/// Reduces fraud and decreases declines. Transactions that do not include a client metadata ID are not eligible for PayPal Seller Protection.
|
||||||
pub client_metadata_id: Option<String>,
|
pub client_metadata_id: Option<String>,
|
||||||
|
/// Identifies the caller as a PayPal partner. To receive revenue attribution, specify a unique build notation (BN) code.
|
||||||
|
/// BN codes provide tracking on all transactions that originate or are associated with a particular partner.
|
||||||
pub partner_attribution_id: Option<String>,
|
pub partner_attribution_id: Option<String>,
|
||||||
|
/// Contains a unique user-generated ID that the server stores for a period of time. Use this header to enforce idempotency on REST API POST calls.
|
||||||
|
/// You can make these calls any number of times without concern that the server creates or completes an action on a resource more than once.
|
||||||
|
/// You can retry calls that fail with network timeouts or the HTTP 500 status code. You can retry calls for as long as the server stores the ID.
|
||||||
pub request_id: Option<String>,
|
pub request_id: Option<String>,
|
||||||
|
/// The preferred server response upon successful completion of the request.
|
||||||
pub prefer: Option<Prefer>,
|
pub prefer: Option<Prefer>,
|
||||||
|
/// The media type. Required for operations with a request body.
|
||||||
pub content_type: Option<String>,
|
pub content_type: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,26 +192,40 @@ impl Client {
|
||||||
headers.append(header::ACCEPT, "application/json".parse().unwrap());
|
headers.append(header::ACCEPT, "application/json".parse().unwrap());
|
||||||
|
|
||||||
if let Some(token) = &self.auth.access_token {
|
if let Some(token) = &self.auth.access_token {
|
||||||
headers.append(header::AUTHORIZATION, format!("Bearer {}", token.access_token).as_str().parse().unwrap());
|
headers.append(
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
format!("Bearer {}", token.access_token).as_str().parse().unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(merchant_payer_id) = header_params.merchant_payer_id {
|
if let Some(merchant_payer_id) = header_params.merchant_payer_id {
|
||||||
let claims = AuthAssertionClaims {
|
let claims = AuthAssertionClaims {
|
||||||
iss: self.auth.client_id.clone(),
|
iss: self.auth.client_id.clone(),
|
||||||
payer_id: merchant_payer_id
|
payer_id: merchant_payer_id,
|
||||||
};
|
};
|
||||||
let jwt_header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::HS256);
|
let jwt_header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::HS256);
|
||||||
let token = jsonwebtoken::encode(&jwt_header, &claims, &jsonwebtoken::EncodingKey::from_secret(self.auth.secret.as_ref())).unwrap();
|
let token = jsonwebtoken::encode(
|
||||||
|
&jwt_header,
|
||||||
|
&claims,
|
||||||
|
&jsonwebtoken::EncodingKey::from_secret(self.auth.secret.as_ref()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let encoded_token = base64::encode(token);
|
let encoded_token = base64::encode(token);
|
||||||
headers.append("PayPal-Auth-Assertion", encoded_token.as_str().parse().unwrap());
|
headers.append("PayPal-Auth-Assertion", encoded_token.as_str().parse().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(client_metadata_id) = header_params.client_metadata_id {
|
if let Some(client_metadata_id) = header_params.client_metadata_id {
|
||||||
headers.append("PayPal-Client-Metadata-Id", client_metadata_id.as_str().parse().unwrap());
|
headers.append(
|
||||||
|
"PayPal-Client-Metadata-Id",
|
||||||
|
client_metadata_id.as_str().parse().unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(partner_attribution_id) = header_params.partner_attribution_id {
|
if let Some(partner_attribution_id) = header_params.partner_attribution_id {
|
||||||
headers.append("PayPal-Partner-Attribution-Id", partner_attribution_id.as_str().parse().unwrap());
|
headers.append(
|
||||||
|
"PayPal-Partner-Attribution-Id",
|
||||||
|
partner_attribution_id.as_str().parse().unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(request_id) = header_params.request_id {
|
if let Some(request_id) = header_params.request_id {
|
||||||
|
@ -219,7 +243,7 @@ impl Client {
|
||||||
headers.append(header::CONTENT_TYPE, content_type.as_str().parse().unwrap());
|
headers.append(header::CONTENT_TYPE, content_type.as_str().parse().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.headers(headers)
|
builder.headers(headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a access token used in all the api calls.
|
/// Gets a access token used in all the api calls.
|
||||||
|
@ -227,10 +251,7 @@ impl Client {
|
||||||
let res = self
|
let res = self
|
||||||
.client
|
.client
|
||||||
.post(format!("{}/v1/oauth2/token", self.endpoint()).as_str())
|
.post(format!("{}/v1/oauth2/token", self.endpoint()).as_str())
|
||||||
.basic_auth(
|
.basic_auth(self.auth.client_id.as_str(), Some(self.auth.secret.as_str()))
|
||||||
self.auth.client_id.as_str(),
|
|
||||||
Some(self.auth.secret.as_str()),
|
|
||||||
)
|
|
||||||
.header("Content-Type", "x-www-form-urlencoded")
|
.header("Content-Type", "x-www-form-urlencoded")
|
||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.body("grant_type=client_credentials")
|
.body("grant_type=client_credentials")
|
||||||
|
@ -242,7 +263,7 @@ impl Client {
|
||||||
self.auth.expires = Some((Instant::now(), Duration::new(token.expires_in, 0)));
|
self.auth.expires = Some((Instant::now(), Duration::new(token.expires_in, 0)));
|
||||||
self.auth.access_token = Some(token);
|
self.auth.access_token = Some(token);
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(errors::Errors::GetAccessTokenFailure));
|
return Err(Box::new(errors::Errors::ApiCallFailure(res.text().await?)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
321
src/orders.rs
321
src/orders.rs
|
@ -1,8 +1,8 @@
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum Intent {
|
pub enum Intent {
|
||||||
/// The merchant intends to capture payment immediately after the customer makes a payment.
|
/// The merchant intends to capture payment immediately after the customer makes a payment.
|
||||||
|
@ -24,7 +24,7 @@ impl Default for Intent {
|
||||||
/// Represents a payer name.
|
/// 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)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct PayerName {
|
pub struct PayerName {
|
||||||
/// When the party is a person, the party's given, or first, name.
|
/// When the party is a person, the party's given, or first, name.
|
||||||
pub given_name: String,
|
pub given_name: String,
|
||||||
|
@ -36,7 +36,7 @@ pub struct PayerName {
|
||||||
/// The phone type.
|
/// 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)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum PhoneType {
|
pub enum PhoneType {
|
||||||
Fax,
|
Fax,
|
||||||
|
@ -46,7 +46,7 @@ pub enum PhoneType {
|
||||||
Pager,
|
Pager,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct PhoneNumber {
|
pub struct PhoneNumber {
|
||||||
/// The national number, in its canonical international E.164 numbering plan format.
|
/// The national number, in its canonical international E.164 numbering plan format.
|
||||||
/// The combined length of the country calling code (CC) and the national number must not be greater than 15 digits.
|
/// The combined length of the country calling code (CC) and the national number must not be greater than 15 digits.
|
||||||
|
@ -63,7 +63,7 @@ pub struct Phone {
|
||||||
pub phone_number: PhoneNumber,
|
pub phone_number: PhoneNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum TaxIdType {
|
pub enum TaxIdType {
|
||||||
|
@ -134,7 +134,7 @@ pub struct Payer {
|
||||||
pub address: Option<Address>,
|
pub address: Option<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct Money {
|
pub struct Money {
|
||||||
/// The [three-character ISO-4217 currency code](https://developer.paypal.com/docs/integration/direct/rest/currency-codes/) that identifies the currency.
|
/// The [three-character ISO-4217 currency code](https://developer.paypal.com/docs/integration/direct/rest/currency-codes/) that identifies the currency.
|
||||||
pub currency_code: String,
|
pub currency_code: String,
|
||||||
|
@ -216,12 +216,12 @@ pub struct PlatformFee {
|
||||||
pub payee: Option<Payee>,
|
pub payee: Option<Payee>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub enum DisbursementMode {
|
pub enum DisbursementMode {
|
||||||
/// The funds are released to the merchant immediately.
|
/// The funds are released to the merchant immediately.
|
||||||
Instant,
|
Instant,
|
||||||
/// The funds are held for a finite number of days. The actual duration depends on the region and type of integration.
|
/// The funds are held for a finite number of days. The actual duration depends on the region and type of integration.
|
||||||
/// You can release the funds through a referenced payout.
|
/// You can release the funds through a referenced payout.
|
||||||
/// Otherwise, the funds disbursed automatically after the specified duration.
|
/// Otherwise, the funds disbursed automatically after the specified duration.
|
||||||
Delayed,
|
Delayed,
|
||||||
}
|
}
|
||||||
|
@ -234,19 +234,19 @@ impl Default for DisbursementMode {
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct PaymentInstruction {
|
pub struct PaymentInstruction {
|
||||||
/// An array of various fees, commissions, tips, or donations.
|
/// An array of various fees, commissions, tips, or donations.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub platform_fees: Option<Vec<PlatformFee>>,
|
pub platform_fees: Option<Vec<PlatformFee>>,
|
||||||
/// The funds that are held on behalf of the merchant.
|
/// The funds that are held on behalf of the merchant.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub disbursement_mode: Option<DisbursementMode>
|
pub disbursement_mode: Option<DisbursementMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum ItemCategoryType {
|
pub enum ItemCategoryType {
|
||||||
/// Goods that are stored, delivered, and used in their electronic format.
|
/// Goods that are stored, delivered, and used in their electronic format.
|
||||||
/// This value is not currently supported for API callers that leverage
|
/// This value is not currently supported for API callers that leverage
|
||||||
/// the [PayPal for Commerce Platform](https://www.paypal.com/us/webapps/mpp/commerce-platform) product.
|
/// the [PayPal for Commerce Platform](https://www.paypal.com/us/webapps/mpp/commerce-platform) product.
|
||||||
Digital,
|
Digital,
|
||||||
/// A tangible item that can be shipped with proof of delivery.
|
/// A tangible item that can be shipped with proof of delivery.
|
||||||
|
@ -272,17 +272,17 @@ pub struct Item {
|
||||||
/// The item name or title.
|
/// The item name or title.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The item price or rate per unit.
|
/// The item price or rate per unit.
|
||||||
/// If you specify unit_amount, purchase_units[].amount.breakdown.item_total is required. Must equal unit_amount * quantity for all items.
|
/// If you specify unit_amount, purchase_units[].amount.breakdown.item_total is required. Must equal unit_amount * quantity for all items.
|
||||||
pub unit_amount: Money,
|
pub unit_amount: Money,
|
||||||
/// The item tax for each unit. If tax is specified, purchase_units[].amount.breakdown.tax_total is required. Must equal tax * quantity for all items.
|
/// The item tax for each unit. If tax is specified, purchase_units[].amount.breakdown.tax_total is required. Must equal tax * quantity for all items.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub tax: Option<Money>,
|
pub tax: Option<Money>,
|
||||||
/// The item quantity. Must be a whole number.
|
/// The item quantity. Must be a whole number.
|
||||||
pub quantity: String,
|
pub quantity: String,
|
||||||
/// The detailed item description.
|
/// The detailed item description.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
/// The stock keeping unit (SKU) for the item.
|
/// The stock keeping unit (SKU) for the item.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sku: Option<String>,
|
pub sku: Option<String>,
|
||||||
/// The item category type
|
/// The item category type
|
||||||
|
@ -290,7 +290,7 @@ pub struct Item {
|
||||||
pub category: Option<ItemCategoryType>,
|
pub category: Option<ItemCategoryType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum AuthorizationStatus {
|
pub enum AuthorizationStatus {
|
||||||
/// The authorized payment is created. No captured payments have been made for this authorized payment.
|
/// The authorized payment is created. No captured payments have been made for this authorized payment.
|
||||||
|
@ -311,22 +311,22 @@ pub enum AuthorizationStatus {
|
||||||
Pending,
|
Pending,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum AuthorizationStatusDetails {
|
pub enum AuthorizationStatusDetails {
|
||||||
/// Authorization is pending manual review.
|
/// Authorization is pending manual review.
|
||||||
PendingReview,
|
PendingReview,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct AuthorizationWithData {
|
pub struct AuthorizationWithData {
|
||||||
/// The status for the authorized payment.
|
/// The status for the authorized payment.
|
||||||
pub status: AuthorizationStatus,
|
pub status: AuthorizationStatus,
|
||||||
/// The details of the authorized order pending status.
|
/// The details of the authorized order pending status.
|
||||||
pub status_details: AuthorizationStatusDetails,
|
pub status_details: AuthorizationStatusDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum CaptureStatus {
|
pub enum CaptureStatus {
|
||||||
/// The funds for this captured payment were credited to the payee's PayPal account.
|
/// The funds for this captured payment were credited to the payee's PayPal account.
|
||||||
|
@ -341,12 +341,12 @@ pub enum CaptureStatus {
|
||||||
Refunded,
|
Refunded,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum CaptureStatusDetails {
|
pub enum CaptureStatusDetails {
|
||||||
/// The payer initiated a dispute for this captured payment with PayPal.
|
/// The payer initiated a dispute for this captured payment with PayPal.
|
||||||
BuyerComplaint,
|
BuyerComplaint,
|
||||||
/// The captured funds were reversed in response to the payer disputing this captured payment with
|
/// The captured funds were reversed in response to the payer disputing this captured payment with
|
||||||
/// the issuer of the financial instrument used to pay for this captured payment.
|
/// the issuer of the financial instrument used to pay for this captured payment.
|
||||||
Chargeback,
|
Chargeback,
|
||||||
/// The payer paid by an eCheck that has not yet cleared.
|
/// The payer paid by an eCheck that has not yet cleared.
|
||||||
|
@ -359,7 +359,7 @@ pub enum CaptureStatusDetails {
|
||||||
PendingReview,
|
PendingReview,
|
||||||
/// The payee has not yet set up appropriate receiving preferences for their account.
|
/// The payee has not yet set up appropriate receiving preferences for their account.
|
||||||
/// For more information about how to accept or deny this payment, visit your account online.
|
/// For more information about how to accept or deny this payment, visit your account online.
|
||||||
/// This reason is typically offered in scenarios such as when the currency of the captured
|
/// This reason is typically offered in scenarios such as when the currency of the captured
|
||||||
/// payment is different from the primary holding currency of the payee.
|
/// payment is different from the primary holding currency of the payee.
|
||||||
ReceivingPreferenceMandatesManualAction,
|
ReceivingPreferenceMandatesManualAction,
|
||||||
/// The captured funds were refunded.
|
/// The captured funds were refunded.
|
||||||
|
@ -372,15 +372,15 @@ pub enum CaptureStatusDetails {
|
||||||
VerificationRequired,
|
VerificationRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct Capture {
|
pub struct Capture {
|
||||||
/// The status of the captured payment.
|
/// The status of the captured payment.
|
||||||
status: CaptureStatus,
|
status: CaptureStatus,
|
||||||
/// The details of the captured payment status.
|
/// The details of the captured payment status.
|
||||||
status_details: CaptureStatusDetails,
|
status_details: CaptureStatusDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum RefundStatus {
|
pub enum RefundStatus {
|
||||||
/// The refund was cancelled.
|
/// The refund was cancelled.
|
||||||
|
@ -392,7 +392,7 @@ pub enum RefundStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The reason why the refund has the PENDING or FAILED status.
|
/// The reason why the refund has the PENDING or FAILED status.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum RefundStatusDetails {
|
pub enum RefundStatusDetails {
|
||||||
/// The customer's account is funded through an eCheck, which has not yet cleared.
|
/// The customer's account is funded through an eCheck, which has not yet cleared.
|
||||||
|
@ -401,19 +401,19 @@ pub enum RefundStatusDetails {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Refund {
|
pub struct Refund {
|
||||||
/// The status of the refund.
|
/// The status of the refund.
|
||||||
pub status: RefundStatus,
|
pub status: RefundStatus,
|
||||||
/// The details of the refund status.
|
/// The details of the refund status.
|
||||||
pub status_details: RefundStatusDetails,
|
pub status_details: RefundStatusDetails,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct PaymentCollection {
|
pub struct PaymentCollection {
|
||||||
/// An array of authorized payments for a purchase unit. A purchase unit can have zero or more authorized payments.
|
/// An array of authorized payments for a purchase unit. A purchase unit can have zero or more authorized payments.
|
||||||
pub authorizations: Vec<AuthorizationWithData>,
|
pub authorizations: Vec<AuthorizationWithData>,
|
||||||
/// An array of captured payments for a purchase unit. A purchase unit can have zero or more captured payments.
|
/// An array of captured payments for a purchase unit. A purchase unit can have zero or more captured payments.
|
||||||
pub captures: Vec<Capture>,
|
pub captures: Vec<Capture>,
|
||||||
/// An array of refunds for a purchase unit. A purchase unit can have zero or more refunds.
|
/// An array of refunds for a purchase unit. A purchase unit can have zero or more refunds.
|
||||||
pub refunds: Vec<Refund>,
|
pub refunds: Vec<Refund>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,24 +436,24 @@ pub struct PurchaseUnit {
|
||||||
pub payee: Option<Payee>,
|
pub payee: Option<Payee>,
|
||||||
/// Any additional payment instructions for PayPal Commerce Platform customers.
|
/// Any additional payment instructions for PayPal Commerce Platform customers.
|
||||||
/// Enables features for the PayPal Commerce Platform, such as delayed disbursement and collection of a platform fee.
|
/// Enables features for the PayPal Commerce Platform, such as delayed disbursement and collection of a platform fee.
|
||||||
/// Applies during order creation for captured payments or during capture of authorized payments.
|
/// Applies during order creation for captured payments or during capture of authorized payments.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payment_instruction: Option<PaymentInstruction>,
|
pub payment_instruction: Option<PaymentInstruction>,
|
||||||
/// The purchase description.
|
/// The purchase description.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
/// The API caller-provided external ID. Used to reconcile client transactions with PayPal transactions.
|
/// The API caller-provided external ID. Used to reconcile client transactions with PayPal transactions.
|
||||||
/// Appears in transaction and settlement reports but is not visible to the payer.
|
/// Appears in transaction and settlement reports but is not visible to the payer.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub custom_id: Option<String>,
|
pub custom_id: Option<String>,
|
||||||
/// The API caller-provided external invoice number for this order.
|
/// The API caller-provided external invoice number for this order.
|
||||||
/// Appears in both the payer's transaction history and the emails that the payer receives.
|
/// Appears in both the payer's transaction history and the emails that the payer receives.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub invoice_id: Option<String>,
|
pub invoice_id: Option<String>,
|
||||||
/// The PayPal-generated ID for the purchase unit.
|
/// The PayPal-generated ID for the purchase unit.
|
||||||
/// This ID appears in both the payer's transaction history and the emails that the payer receives.
|
/// This ID appears in both the payer's transaction history and the emails that the payer receives.
|
||||||
/// In addition, this ID is available in transaction and settlement reports that merchants and API callers can use to reconcile transactions.
|
/// In addition, this ID is available in transaction and settlement reports that merchants and API callers can use to reconcile transactions.
|
||||||
/// This ID is only available when an order is saved by calling v2/checkout/orders/id/save.
|
/// This ID is only available when an order is saved by calling v2/checkout/orders/id/save.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub id: Option<String>,
|
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.
|
/// The soft descriptor is the dynamic text used to construct the statement descriptor that appears on a payer's card statement.
|
||||||
|
@ -461,10 +461,10 @@ pub struct PurchaseUnit {
|
||||||
/// 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
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub soft_descriptor: Option<String>,
|
pub soft_descriptor: Option<String>,
|
||||||
/// An array of items that the customer purchases from the merchant.
|
/// An array of items that the customer purchases from the merchant.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub items: Option<Vec<Item>>,
|
pub items: Option<Vec<Item>>,
|
||||||
/// The name and address of the person to whom to ship the items.
|
/// The name and address of the person to whom to ship the items.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub shipping: Option<ShippingDetail>,
|
pub shipping: Option<ShippingDetail>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
@ -480,17 +480,17 @@ impl PurchaseUnit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of landing page to show on the PayPal site for customer checkout.
|
/// The type of landing page to show on the PayPal site for customer checkout.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum LandingPage {
|
pub enum LandingPage {
|
||||||
/// When the customer clicks PayPal Checkout, the customer is redirected to a page to log in to PayPal and approve the payment.
|
/// When the customer clicks PayPal Checkout, the customer is redirected to a page to log in to PayPal and approve the payment.
|
||||||
Login,
|
Login,
|
||||||
/// When the customer clicks PayPal Checkout, the customer is redirected to a page
|
/// When the customer clicks PayPal Checkout, the customer is redirected to a page
|
||||||
/// to enter credit or debit card and other relevant billing information required to complete the purchase.
|
/// to enter credit or debit card and other relevant billing information required to complete the purchase.
|
||||||
Billing,
|
Billing,
|
||||||
/// When the customer clicks PayPal Checkout, the customer is redirected to either a page to log in to PayPal and approve
|
/// When the customer clicks PayPal Checkout, the customer is redirected to either a page to log in to PayPal and approve
|
||||||
/// the payment or to a page to enter credit or debit card and other relevant billing information required to complete the purchase,
|
/// the payment or to a page to enter credit or debit card and other relevant billing information required to complete the purchase,
|
||||||
/// depending on their previous interaction with PayPal.
|
/// depending on their previous interaction with PayPal.
|
||||||
NoPreference,
|
NoPreference,
|
||||||
}
|
}
|
||||||
|
@ -502,7 +502,7 @@ impl Default for LandingPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shipping preference
|
/// The shipping preference
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum ShippingPreference {
|
pub enum ShippingPreference {
|
||||||
/// Use the customer-provided shipping address on the PayPal site.
|
/// Use the customer-provided shipping address on the PayPal site.
|
||||||
|
@ -519,7 +519,7 @@ impl Default for ShippingPreference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum UserAction {
|
pub enum UserAction {
|
||||||
/// After you redirect the customer to the PayPal payment page, a Continue button appears. Use this option when
|
/// After you redirect the customer to the PayPal payment page, a Continue button appears. Use this option when
|
||||||
|
@ -527,7 +527,7 @@ pub enum UserAction {
|
||||||
/// to the merchant page without processing the payment.
|
/// to the merchant page without processing the payment.
|
||||||
Continue,
|
Continue,
|
||||||
/// After you redirect the customer to the PayPal payment page, a Pay Now button appears.
|
/// After you redirect the customer to the PayPal payment page, a Pay Now button appears.
|
||||||
/// Use this option when the final amount is known when the checkout is initiated and you want to
|
/// Use this option when the final amount is known when the checkout is initiated and you want to
|
||||||
/// process the payment immediately when the customer clicks Pay Now.
|
/// process the payment immediately when the customer clicks Pay Now.
|
||||||
PayNow,
|
PayNow,
|
||||||
}
|
}
|
||||||
|
@ -538,13 +538,13 @@ impl Default for UserAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum PayeePreferred {
|
pub enum PayeePreferred {
|
||||||
/// Accepts any type of payment from the customer.
|
/// Accepts any type of payment from the customer.
|
||||||
Unrestricted,
|
Unrestricted,
|
||||||
/// Accepts only immediate payment from the customer.
|
/// Accepts only immediate payment from the customer.
|
||||||
/// For example, credit card, PayPal balance, or instant ACH.
|
/// For example, credit card, PayPal balance, or instant ACH.
|
||||||
/// Ensures that at the time of capture, the payment does not have the `pending` status.
|
/// Ensures that at the time of capture, the payment does not have the `pending` status.
|
||||||
ImmediatePaymentRequired,
|
ImmediatePaymentRequired,
|
||||||
}
|
}
|
||||||
|
@ -565,12 +565,12 @@ pub struct PaymentMethod {
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct ApplicationContext {
|
pub struct ApplicationContext {
|
||||||
/// The label that overrides the business name in the PayPal account on the PayPal site.
|
/// The label that overrides the business name in the PayPal account on the PayPal site.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub brand_name: Option<String>,
|
pub brand_name: Option<String>,
|
||||||
/// The BCP 47-formatted locale of pages that the PayPal payment experience shows. PayPal supports a five-character code.
|
/// The BCP 47-formatted locale of pages that the PayPal payment experience shows. PayPal supports a five-character code.
|
||||||
///
|
///
|
||||||
/// For example, da-DK, he-IL, id-ID, ja-JP, no-NO, pt-BR, ru-RU, sv-SE, th-TH, zh-CN, zh-HK, or zh-TW.
|
/// For example, da-DK, he-IL, id-ID, ja-JP, no-NO, pt-BR, ru-RU, sv-SE, th-TH, zh-CN, zh-HK, or zh-TW.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub locale: Option<String>,
|
pub locale: Option<String>,
|
||||||
/// The type of landing page to show on the PayPal site for customer checkout
|
/// The type of landing page to show on the PayPal site for customer checkout
|
||||||
|
@ -582,13 +582,13 @@ pub struct ApplicationContext {
|
||||||
/// Configures a Continue or Pay Now checkout flow.
|
/// Configures a Continue or Pay Now checkout flow.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub user_action: Option<UserAction>,
|
pub user_action: Option<UserAction>,
|
||||||
/// The customer and merchant payment preferences.
|
/// The customer and merchant payment preferences.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payment_method: Option<PaymentMethod>,
|
pub payment_method: Option<PaymentMethod>,
|
||||||
/// The URL where the customer is redirected after the customer approves the payment.
|
/// The URL where the customer is redirected after the customer approves the payment.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub return_url: Option<String>,
|
pub return_url: Option<String>,
|
||||||
/// The URL where the customer is redirected after the customer cancels the payment.
|
/// The URL where the customer is redirected after the customer cancels the payment.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub cancel_url: Option<String>,
|
pub cancel_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -597,13 +597,13 @@ pub struct ApplicationContext {
|
||||||
pub struct OrderPayload {
|
pub struct OrderPayload {
|
||||||
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
||||||
pub intent: Intent,
|
pub intent: Intent,
|
||||||
/// The customer who approves and pays for the order. The customer is also known as the payer.
|
/// The customer who approves and pays for the order. The customer is also known as the payer.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payer: Option<Payer>,
|
pub payer: Option<Payer>,
|
||||||
/// An array of purchase units. Each purchase unit establishes a contract between a payer and the payee.
|
/// An array of purchase units. Each purchase unit establishes a contract between a payer and the payee.
|
||||||
/// Each purchase unit represents either a full or partial order that the payer intends to purchase from the payee.
|
/// Each purchase unit represents either a full or partial order that the payer intends to purchase from the payee.
|
||||||
pub purchase_units: Vec<PurchaseUnit>,
|
pub purchase_units: Vec<PurchaseUnit>,
|
||||||
/// Customize the payer experience during the approval process for the payment with PayPal.
|
/// Customize the payer experience during the approval process for the payment with PayPal.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub application_context: Option<ApplicationContext>,
|
pub application_context: Option<ApplicationContext>,
|
||||||
}
|
}
|
||||||
|
@ -618,8 +618,8 @@ impl OrderPayload {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The card brand or network.
|
/// The card brand or network.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum CardBrand {
|
pub enum CardBrand {
|
||||||
/// Visa card.
|
/// Visa card.
|
||||||
|
@ -656,28 +656,28 @@ pub enum CardBrand {
|
||||||
ChinaUnionPay,
|
ChinaUnionPay,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum CardType {
|
pub enum CardType {
|
||||||
Credit,
|
Credit,
|
||||||
Debit,
|
Debit,
|
||||||
Prepaid,
|
Prepaid,
|
||||||
Unknown
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct CardResponse {
|
pub struct CardResponse {
|
||||||
/// The last digits of the payment card.
|
/// The last digits of the payment card.
|
||||||
pub last_digits: String,
|
pub last_digits: String,
|
||||||
/// The card brand or network.
|
/// The card brand or network.
|
||||||
pub brand: CardBrand,
|
pub brand: CardBrand,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub card_type: CardType,
|
pub card_type: CardType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct WalletResponse {
|
pub struct WalletResponse {
|
||||||
pub apple_pay: CardResponse
|
pub apple_pay: CardResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -686,7 +686,7 @@ pub struct PaymentSourceResponse {
|
||||||
pub wallet: WalletResponse,
|
pub wallet: WalletResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum OrderStatus {
|
pub enum OrderStatus {
|
||||||
/// The order was created with the specified context.
|
/// The order was created with the specified context.
|
||||||
|
@ -702,7 +702,7 @@ pub enum OrderStatus {
|
||||||
Completed,
|
Completed,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum LinkMethod {
|
pub enum LinkMethod {
|
||||||
Get,
|
Get,
|
||||||
|
@ -712,17 +712,16 @@ pub enum LinkMethod {
|
||||||
Head,
|
Head,
|
||||||
Connect,
|
Connect,
|
||||||
Options,
|
Options,
|
||||||
Patch
|
Patch,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct LinkDescription {
|
pub struct LinkDescription {
|
||||||
/// The complete target URL.
|
/// The complete target URL.
|
||||||
pub href: String,
|
pub href: String,
|
||||||
/// The link relation type, which serves as an ID for a link that unambiguously describes the semantics of the link.
|
/// The link relation type, which serves as an ID for a link that unambiguously describes the semantics of the link.
|
||||||
pub rel: String,
|
pub rel: String,
|
||||||
/// The HTTP method required to make the related call.
|
/// The HTTP method required to make the related call.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub method: Option<LinkMethod>,
|
pub method: Option<LinkMethod>,
|
||||||
}
|
}
|
||||||
|
@ -743,45 +742,189 @@ pub struct Order {
|
||||||
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
/// The customer who approves and pays for the order. The customer is also known as the payer.
|
/// The customer who approves and pays for the order. The customer is also known as the payer.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payer: Option<Payer>,
|
pub payer: Option<Payer>,
|
||||||
/// An array of purchase units. Each purchase unit establishes a contract between a customer and merchant.
|
/// An array of purchase units. Each purchase unit establishes a contract between a customer and merchant.
|
||||||
/// Each purchase unit represents either a full or partial order that the customer intends to purchase from the merchant.
|
/// Each purchase unit represents either a full or partial order that the customer intends to purchase from the merchant.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub purchase_units: Option<Vec<PurchaseUnit>>,
|
pub purchase_units: Option<Vec<PurchaseUnit>>,
|
||||||
/// The order status.
|
/// The order status.
|
||||||
pub status: OrderStatus,
|
pub status: OrderStatus,
|
||||||
/// An array of request-related HATEOAS links. To complete payer approval, use the approve link to redirect the payer.
|
/// An array of request-related HATEOAS links. To complete payer approval, use the approve link to redirect the payer.
|
||||||
pub links: Vec<LinkDescription>,
|
pub links: Vec<LinkDescription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Client {
|
impl super::Client {
|
||||||
/// Creates an order. Supports orders with only one purchase unit.
|
/// Creates an order. Supports orders with only one purchase unit.
|
||||||
pub async fn create_order(&self, order: OrderPayload, header_params: crate::HeaderParams) -> Result<Order, Box<dyn std::error::Error>> {
|
pub async fn create_order(
|
||||||
let builder = self.setup_headers(self.client.post(format!("{}/v2/checkout/orders", self.endpoint()).as_str()), header_params);
|
&self,
|
||||||
|
order: OrderPayload,
|
||||||
|
header_params: crate::HeaderParams,
|
||||||
|
) -> Result<Order, Box<dyn std::error::Error>> {
|
||||||
|
let builder = {
|
||||||
|
self.setup_headers(
|
||||||
|
self.client
|
||||||
|
.post(format!("{}/v2/checkout/orders", self.endpoint()).as_str()),
|
||||||
|
header_params,
|
||||||
|
)
|
||||||
|
};
|
||||||
let res = builder.json(&order).send().await?;
|
let res = builder.json(&order).send().await?;
|
||||||
|
|
||||||
if res.status().is_success() {
|
if res.status().is_success() {
|
||||||
let order: Order = res.json::<Order>().await?;
|
let order = res.json::<Order>().await?;
|
||||||
Ok(order)
|
Ok(order)
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(errors::Errors::ApiCallFailure))
|
Err(Box::new(errors::Errors::ApiCallFailure(res.text().await?)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used internally for order requests that have no body.
|
||||||
|
async fn build_endpoint_order<S: std::fmt::Display, A: std::fmt::Display>(
|
||||||
|
&self,
|
||||||
|
order_id: S,
|
||||||
|
endpoint: A,
|
||||||
|
post: bool,
|
||||||
|
header_params: crate::HeaderParams,
|
||||||
|
) -> Result<Order, Box<dyn std::error::Error>> {
|
||||||
|
let format = format!("{}/v2/checkout/orders/{}/{}", self.endpoint(), order_id, endpoint);
|
||||||
|
|
||||||
|
let builder = self.setup_headers(
|
||||||
|
match post {
|
||||||
|
true => self.client.post(format.as_str()),
|
||||||
|
false => self.client.get(format.as_str()),
|
||||||
|
},
|
||||||
|
header_params,
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = builder.send().await?;
|
||||||
|
|
||||||
|
if res.status().is_success() {
|
||||||
|
let order = res.json::<Order>().await?;
|
||||||
|
Ok(order)
|
||||||
|
} else {
|
||||||
|
Err(Box::new(errors::Errors::ApiCallFailure(res.text().await?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates an order with the CREATED or APPROVED status.
|
/// Updates an order with the CREATED or APPROVED status.
|
||||||
///
|
|
||||||
/// You cannot update an order with the COMPLETED status.
|
/// You cannot update an order with the COMPLETED status.
|
||||||
///
|
///
|
||||||
/// TODO: Use a enum for status. https://developer.paypal.com/docs/api/orders/v2/#orders_patch
|
/// Only replacing the existing purchase units and intent is supported right now.
|
||||||
pub async fn update_order<S: AsRef<str>>(&self, id: S, status: S) {
|
///
|
||||||
todo!()
|
/// Note: You can only update the intent from Authorize to Capture
|
||||||
|
///
|
||||||
|
/// More info on what you can change: https://developer.paypal.com/docs/api/orders/v2/#orders_patch
|
||||||
|
pub async fn update_order<S: std::fmt::Display>(
|
||||||
|
&self,
|
||||||
|
id: S,
|
||||||
|
intent: Option<Intent>,
|
||||||
|
purchase_units: Option<Vec<PurchaseUnit>>,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut intent_json = String::new();
|
||||||
|
let units_json = String::new();
|
||||||
|
|
||||||
|
if let Some(p_units) = purchase_units {
|
||||||
|
let mut units_json = String::new();
|
||||||
|
|
||||||
|
for (i, unit) in p_units.iter().enumerate() {
|
||||||
|
let unit_str = serde_json::to_string(&unit)?;
|
||||||
|
let mut unit_json = format!(r#"
|
||||||
|
{{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/purchase_units/@reference_id='{reference_id}'",
|
||||||
|
"value": {unit}
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
reference_id = unit.reference_id.clone().unwrap_or(String::from("default")),
|
||||||
|
unit = unit_str);
|
||||||
|
|
||||||
|
if i < p_units.len() - 1 {
|
||||||
|
unit_json += ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
units_json += unit_json.as_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(x) = intent {
|
||||||
|
let intent_str = match x {
|
||||||
|
Intent::Authorize => String::from("AUTHORIZE"),
|
||||||
|
Intent::Capture => String::from("CAPTURE")
|
||||||
|
};
|
||||||
|
|
||||||
|
intent_json = format!(
|
||||||
|
r#"
|
||||||
|
{{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/intent",
|
||||||
|
"value": "{intent}"
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
intent = intent_str
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let final_json = {
|
||||||
|
if intent_json != "" && units_json != "" {
|
||||||
|
format!("[{},{}]", intent_json, units_json)
|
||||||
|
} else {
|
||||||
|
format!("[{}{}]", intent_json, units_json)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let builder = {
|
||||||
|
self.setup_headers(
|
||||||
|
self.client
|
||||||
|
.patch(format!("{}/v2/checkout/orders/{}", self.endpoint(), id).as_str()),
|
||||||
|
crate::HeaderParams {
|
||||||
|
content_type: Some(String::from("application/json")),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = builder.body(final_json.clone()).send().await?;
|
||||||
|
|
||||||
|
if res.status().is_success() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Box::new(errors::Errors::ApiCallFailure(res.text().await?)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_order<S: AsRef<str>>(id: S) {
|
/// Shows details for an order, by ID.
|
||||||
todo!()
|
pub async fn show_order_details<S: std::fmt::Display>(
|
||||||
|
&self,
|
||||||
|
order_id: S,
|
||||||
|
) -> Result<Order, Box<dyn std::error::Error>> {
|
||||||
|
self.build_endpoint_order(order_id, "", false, crate::HeaderParams::default())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Captures payment for an order. To successfully capture payment for an order,
|
||||||
|
/// the buyer must first approve the order or a valid payment_source must be provided in the request.
|
||||||
|
/// A buyer can approve the order upon being redirected to the rel:approve URL that was returned in the HATEOAS links in the create order response.
|
||||||
|
pub async fn capture_order<S: std::fmt::Display>(
|
||||||
|
&self,
|
||||||
|
order_id: S,
|
||||||
|
header_params: crate::HeaderParams,
|
||||||
|
) -> Result<Order, Box<dyn std::error::Error>> {
|
||||||
|
self.build_endpoint_order(order_id, "capture", true, header_params)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Authorizes payment for an order. To successfully authorize payment for an order,
|
||||||
|
/// the buyer must first approve the order or a valid payment_source must be provided in the request.
|
||||||
|
/// A buyer can approve the order upon being redirected to the rel:approve URL that was returned in the HATEOAS links in the create order response.
|
||||||
|
pub async fn authorize_order<S: std::fmt::Display>(
|
||||||
|
&self,
|
||||||
|
order_id: S,
|
||||||
|
header_params: crate::HeaderParams,
|
||||||
|
) -> Result<Order, Box<dyn std::error::Error>> {
|
||||||
|
self.build_endpoint_order(order_id, "authorize", true, header_params)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Finish order https://developer.paypal.com/docs/api/orders/v2/
|
// TODO: Add strong typed support for order errors in body: https://developer.paypal.com/docs/api/orders/v2/#errors
|
||||||
|
|
17
src/tests.rs
17
src/tests.rs
|
@ -14,16 +14,25 @@ async fn it_works() {
|
||||||
false,
|
false,
|
||||||
"should not error"
|
"should not error"
|
||||||
);
|
);
|
||||||
println!("{:#?}", client);
|
|
||||||
|
|
||||||
let order = orders::OrderPayload::new(
|
let order = orders::OrderPayload::new(
|
||||||
orders::Intent::Capture,
|
orders::Intent::Authorize,
|
||||||
vec![orders::PurchaseUnit::new(orders::Amount::new(
|
vec![orders::PurchaseUnit::new(orders::Amount::new(
|
||||||
"EUR", "10.0",
|
"EUR", "10.0",
|
||||||
))],
|
))],
|
||||||
);
|
);
|
||||||
|
|
||||||
let order_created = client.create_order(order, HeaderParams::default()).await.unwrap();
|
let ref_id = format!("TEST-{:?}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs());
|
||||||
|
|
||||||
println!("{:#?}", order_created);
|
let order_created = client.create_order(order, HeaderParams {
|
||||||
|
prefer: Some(Prefer::Representation),
|
||||||
|
request_id: Some(ref_id.clone()),
|
||||||
|
..Default::default()
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
assert!(order_created.id != "", "order id is not empty");
|
||||||
|
assert_eq!(order_created.status, orders::OrderStatus::Created, "order status is created");
|
||||||
|
assert_eq!(order_created.links.len(), 4, "order links exist");
|
||||||
|
|
||||||
|
client.update_order(order_created.id, Some(orders::Intent::Capture), Some(order_created.purchase_units.expect("to exist"))).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue