create_order
This commit is contained in:
parent
5d5c7d0cfa
commit
42e5396ad0
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "paypal-rs"
|
name = "paypal-rs"
|
||||||
version = "0.0.3"
|
version = "0.0.4"
|
||||||
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/"
|
||||||
|
@ -20,4 +20,5 @@ jsonwebtoken = "7"
|
||||||
base64 = "0.12"
|
base64 = "0.12"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
thiserror = "1.0"
|
|
@ -1,5 +1,6 @@
|
||||||
# paypal-rs
|
# paypal-rs
|
||||||
![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)
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
use std::fmt;
|
use thiserror::Error;
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Error)]
|
||||||
pub struct GetAccessTokenError;
|
pub enum Errors {
|
||||||
|
#[error("failed to get access token")]
|
||||||
impl fmt::Display for GetAccessTokenError {
|
GetAccessTokenFailure,
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
#[error("failure when calling the paypal api")]
|
||||||
write!(f, "error getting access token")
|
ApiCallFailure,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for GetAccessTokenError {}
|
|
79
src/lib.rs
79
src/lib.rs
|
@ -14,32 +14,46 @@ use reqwest::header;
|
||||||
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";
|
||||||
|
|
||||||
/// Represents the access token returned by the oauth2 authentication.
|
/// 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)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct AccessToken {
|
pub struct AccessToken {
|
||||||
|
/// The OAuth2 scopes.
|
||||||
pub scope: String,
|
pub scope: String,
|
||||||
|
/// The access token.
|
||||||
pub access_token: String,
|
pub access_token: String,
|
||||||
|
/// The token type.
|
||||||
pub token_type: String,
|
pub token_type: String,
|
||||||
|
/// The app id.
|
||||||
pub app_id: String,
|
pub app_id: String,
|
||||||
|
/// Seconds until it expires.
|
||||||
pub expires_in: u64,
|
pub expires_in: u64,
|
||||||
|
/// The nonce.
|
||||||
pub nonce: String,
|
pub nonce: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stores OAuth2 information.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
|
/// Your client id.
|
||||||
pub client_id: String,
|
pub client_id: String,
|
||||||
|
/// The secret.
|
||||||
pub secret: String,
|
pub secret: String,
|
||||||
|
/// The access token returned by oauth2 authentication.
|
||||||
pub access_token: Option<AccessToken>,
|
pub access_token: Option<AccessToken>,
|
||||||
|
/// Used to check when the token expires.
|
||||||
pub expires: Option<(Instant, Duration)>,
|
pub expires: Option<(Instant, Duration)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a client used to interact with the paypal api.
|
/// Represents a client used to interact with the paypal api.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
|
/// Internal http client
|
||||||
pub client: reqwest::Client,
|
pub client: reqwest::Client,
|
||||||
|
/// Whether you are or not in a sandbox enviroment.
|
||||||
pub sandbox: bool,
|
pub sandbox: bool,
|
||||||
|
/// Api Auth information
|
||||||
pub auth: Auth,
|
pub auth: Auth,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,26 +65,60 @@ pub struct Client {
|
||||||
/// ```
|
/// ```
|
||||||
/// let query = Query { count: Some(40), ..Default::default() };
|
/// let query = Query { count: Some(40), ..Default::default() };
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize)]
|
||||||
pub struct Query {
|
pub struct Query {
|
||||||
|
/// The number of items to list in the response.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub count: Option<i32>,
|
pub count: Option<i32>,
|
||||||
|
/// The end date and time for the range to show in the response.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub end_time: Option<chrono::DateTime<chrono::Utc>>,
|
pub end_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
|
/// The page number indicating which set of items will be returned in the response.
|
||||||
|
/// So, the combination of page=1 and page_size=20 returns the first 20 items.
|
||||||
|
/// The combination of page=2 and page_size=20 returns items 21 through 40.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub page: Option<i32>,
|
pub page: Option<i32>,
|
||||||
|
/// The number of items to return in the response.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub page_size: Option<i32>,
|
pub page_size: Option<i32>,
|
||||||
|
/// Indicates whether to show the total count in the response.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub total_count_required: Option<bool>,
|
pub total_count_required: Option<bool>,
|
||||||
|
/// Sorts the payments in the response by a specified value, such as the create time or update time.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sort_by: Option<String>,
|
pub sort_by: Option<String>,
|
||||||
|
/// Sorts the items in the response in ascending or descending order.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sort_order: Option<String>,
|
pub sort_order: Option<String>,
|
||||||
|
/// The ID of the starting resource in the response.
|
||||||
|
/// 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")]
|
||||||
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.
|
||||||
|
/// For example, to start at the second item in a list of results, specify start_index=2.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub start_index: Option<i32>,
|
pub start_index: Option<i32>,
|
||||||
|
/// The start date and time for the range to show in the response.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub start_time: Option<chrono::DateTime<chrono::Utc>>,
|
pub start_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
|
// TODO: Use https://github.com/samscott89/serde_qs
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Prefer {
|
pub enum Prefer {
|
||||||
|
/// 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.
|
||||||
Minimal,
|
Minimal,
|
||||||
|
/// The server returns a complete resource representation, including the current state of the resource.
|
||||||
Representation,
|
Representation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Prefer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Prefer::Minimal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents the optional header values used on paypal requests.
|
/// 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
|
||||||
|
@ -96,21 +144,15 @@ impl Client {
|
||||||
/// Example:
|
/// Example:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #[tokio::main]
|
/// let clientid = env::var("PAYPAL_CLIENTID").unwrap();
|
||||||
/// async fn main() {
|
/// let secret = env::var("PAYPAL_SECRET").unwrap();
|
||||||
/// dotenv().ok();
|
|
||||||
/// let clientid = env::var("PAYPAL_CLIENTID").unwrap();
|
|
||||||
/// let secret = env::var("PAYPAL_SECRET").unwrap();
|
|
||||||
///
|
///
|
||||||
/// let mut client = Client::new(
|
/// let mut client = Client::new(
|
||||||
/// clientid.as_str(),
|
/// clientid.as_str(),
|
||||||
/// secret.as_str(),
|
/// secret.as_str(),
|
||||||
/// true,
|
/// true,
|
||||||
/// );
|
/// );
|
||||||
///
|
/// client.get_access_token().await.unwrap();
|
||||||
/// client.get_access_token().await.unwrap();
|
|
||||||
/// println!("{:#?}", client);
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new<S: Into<String>>(client_id: S, secret: S, sandbox: bool) -> Client {
|
pub fn new<S: Into<String>>(client_id: S, secret: S, sandbox: bool) -> Client {
|
||||||
Client {
|
Client {
|
||||||
|
@ -199,11 +241,8 @@ impl Client {
|
||||||
let token = res.json::<AccessToken>().await?;
|
let token = res.json::<AccessToken>().await?;
|
||||||
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);
|
||||||
println!("{:#?}", self.auth);
|
|
||||||
} else {
|
} else {
|
||||||
println!("status = {:#?}", res.status());
|
return Err(Box::new(errors::Errors::GetAccessTokenFailure));
|
||||||
println!("res = {:#?}", res);
|
|
||||||
return Err(Box::new(errors::GetAccessTokenError));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
455
src/orders.rs
455
src/orders.rs
|
@ -1,5 +1,9 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
/// 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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[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.
|
||||||
Capture,
|
Capture,
|
||||||
|
@ -20,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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
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,
|
||||||
|
@ -32,7 +36,8 @@ 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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum PhoneType {
|
pub enum PhoneType {
|
||||||
Fax,
|
Fax,
|
||||||
Home,
|
Home,
|
||||||
|
@ -41,7 +46,7 @@ pub enum PhoneType {
|
||||||
Pager,
|
Pager,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
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.
|
||||||
|
@ -51,13 +56,15 @@ pub struct PhoneNumber {
|
||||||
|
|
||||||
/// The phone number of the customer. Available only when you enable the
|
/// The phone number of the customer. Available only when you enable the
|
||||||
/// Contact Telephone Number option in the Profile & Settings for the merchant's PayPal account.
|
/// Contact Telephone Number option in the Profile & Settings for the merchant's PayPal account.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Phone {
|
pub struct Phone {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub phone_type: Option<PhoneType>,
|
pub phone_type: Option<PhoneType>,
|
||||||
pub phone_number: PhoneNumber,
|
pub phone_number: PhoneNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum TaxIdType {
|
pub enum TaxIdType {
|
||||||
/// The individual tax ID type.
|
/// The individual tax ID type.
|
||||||
|
@ -66,7 +73,7 @@ pub enum TaxIdType {
|
||||||
BR_CNPJ,
|
BR_CNPJ,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct TaxInfo {
|
pub struct TaxInfo {
|
||||||
/// The customer's tax ID. Supported for the PayPal payment method only.
|
/// The customer's tax ID. Supported for the PayPal payment method only.
|
||||||
/// Typically, the tax ID is 11 characters long for individuals and 14 characters long for businesses.
|
/// Typically, the tax ID is 11 characters long for individuals and 14 characters long for businesses.
|
||||||
|
@ -75,19 +82,24 @@ pub struct TaxInfo {
|
||||||
pub tax_id_type: TaxIdType,
|
pub tax_id_type: TaxIdType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Address {
|
pub struct Address {
|
||||||
/// The first line of the address. For example, number or street. For example, 173 Drury Lane.
|
/// The first line of the address. For example, number or street. For example, 173 Drury Lane.
|
||||||
/// Required for data entry and compliance and risk checks. Must contain the full address.
|
/// Required for data entry and compliance and risk checks. Must contain the full address.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address_line_1: Option<String>,
|
pub address_line_1: Option<String>,
|
||||||
/// The second line of the address. For example, suite or apartment number.
|
/// The second line of the address. For example, suite or apartment number.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address_line_2: Option<String>,
|
pub address_line_2: Option<String>,
|
||||||
/// A city, town, or village. Smaller than admin_area_level_1.
|
/// A city, town, or village. Smaller than admin_area_level_1.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub admin_area_2: Option<String>,
|
pub admin_area_2: Option<String>,
|
||||||
/// The highest level sub-division in a country, which is usually a province, state, or ISO-3166-2 subdivision.
|
/// The highest level sub-division in a country, which is usually a province, state, or ISO-3166-2 subdivision.
|
||||||
/// Format for postal delivery. For example, CA and not California.
|
/// Format for postal delivery. For example, CA and not California.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub admin_area_1: Option<String>,
|
pub admin_area_1: Option<String>,
|
||||||
/// The postal code, which is the zip code or equivalent. Typically required for countries with a postal code or an equivalent.
|
/// The postal code, which is the zip code or equivalent. Typically required for countries with a postal code or an equivalent.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub postal_code: Option<String>,
|
pub postal_code: Option<String>,
|
||||||
/// The two-character [ISO 3166-1](https://developer.paypal.com/docs/api/reference/country-codes/) code that identifies the country or region.
|
/// The two-character [ISO 3166-1](https://developer.paypal.com/docs/api/reference/country-codes/) code that identifies the country or region.
|
||||||
pub country_code: String,
|
pub country_code: String,
|
||||||
|
@ -96,26 +108,33 @@ pub struct Address {
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// https://developer.paypal.com/docs/api/orders/v2/#definition-payer
|
/// https://developer.paypal.com/docs/api/orders/v2/#definition-payer
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Payer {
|
pub struct Payer {
|
||||||
/// The name of the payer.
|
/// The name of the payer.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub name: Option<PayerName>,
|
pub name: Option<PayerName>,
|
||||||
/// The email address of the payer.
|
/// The email address of the payer.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub email_address: Option<String>,
|
pub email_address: Option<String>,
|
||||||
/// The PayPal-assigned ID for the payer.
|
/// The PayPal-assigned ID for the payer.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payer_id: Option<String>,
|
pub payer_id: Option<String>,
|
||||||
/// The phone number of the customer. Available only when you enable the Contact
|
/// The phone number of the customer. Available only when you enable the Contact
|
||||||
/// Telephone Number option in the Profile & Settings for the merchant's PayPal account.
|
/// Telephone Number option in the Profile & Settings for the merchant's PayPal account.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub phone: Option<Phone>,
|
pub phone: Option<Phone>,
|
||||||
/// The birth date of the payer in YYYY-MM-DD format.
|
/// The birth date of the payer in YYYY-MM-DD format.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub birth_date: Option<String>,
|
pub birth_date: Option<String>,
|
||||||
/// The tax information of the payer. Required only for Brazilian payer's.
|
/// The tax information of the payer. Required only for Brazilian payer's.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub tax_info: Option<TaxInfo>,
|
pub tax_info: Option<TaxInfo>,
|
||||||
/// The address of the payer.
|
/// The address of the payer.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address: Option<Address>,
|
pub address: Option<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
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,
|
||||||
|
@ -128,26 +147,33 @@ pub struct Money {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Breakdown provides details such as total item amount, total tax amount, shipping, handling, insurance, and discounts, if any.
|
/// Breakdown provides details such as total item amount, total tax amount, shipping, handling, insurance, and discounts, if any.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Breakdown {
|
pub struct Breakdown {
|
||||||
/// The subtotal for all items. Required if the request includes purchase_units[].items[].unit_amount.
|
/// The subtotal for all items. Required if the request includes purchase_units[].items[].unit_amount.
|
||||||
/// Must equal the sum of (items[].unit_amount * items[].quantity) for all items.
|
/// Must equal the sum of (items[].unit_amount * items[].quantity) for all items.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub item_total: Option<Money>,
|
pub item_total: Option<Money>,
|
||||||
/// The shipping fee for all items within a given purchase_unit.
|
/// The shipping fee for all items within a given purchase_unit.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub shipping: Option<Money>,
|
pub shipping: Option<Money>,
|
||||||
/// The handling fee for all items within a given purchase_unit.
|
/// The handling fee for all items within a given purchase_unit.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub handling: Option<Money>,
|
pub handling: Option<Money>,
|
||||||
/// The total tax for all items. Required if the request includes purchase_units.items.tax. Must equal the sum of (items[].tax * items[].quantity) for all items.
|
/// The total tax for all items. Required if the request includes purchase_units.items.tax. Must equal the sum of (items[].tax * items[].quantity) for all items.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub tax_total: Option<Money>,
|
pub tax_total: Option<Money>,
|
||||||
/// The insurance fee for all items within a given purchase_unit.
|
/// The insurance fee for all items within a given purchase_unit.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub insurance: Option<Money>,
|
pub insurance: Option<Money>,
|
||||||
/// The shipping discount for all items within a given purchase_unit.
|
/// The shipping discount for all items within a given purchase_unit.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub shipping_discount: Option<Money>,
|
pub shipping_discount: Option<Money>,
|
||||||
/// The discount for all items within a given purchase_unit.
|
/// The discount for all items within a given purchase_unit.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub discount: Option<Money>,
|
pub discount: Option<Money>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Amount {
|
pub struct Amount {
|
||||||
/// 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,
|
||||||
|
@ -158,24 +184,39 @@ pub struct Amount {
|
||||||
/// For the required number of decimal places for a currency code, see [Currency Codes](https://developer.paypal.com/docs/api/reference/currency-codes/).
|
/// For the required number of decimal places for a currency code, see [Currency Codes](https://developer.paypal.com/docs/api/reference/currency-codes/).
|
||||||
pub value: String,
|
pub value: String,
|
||||||
/// The breakdown of the amount.
|
/// The breakdown of the amount.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub breakdown: Option<Breakdown>,
|
pub breakdown: Option<Breakdown>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
impl Amount {
|
||||||
|
/// Creates a new amount with the required values.
|
||||||
|
pub fn new<S: Into<String>>(currency_code: S, value: S) -> Self {
|
||||||
|
Amount {
|
||||||
|
currency_code: currency_code.into(),
|
||||||
|
value: value.into(),
|
||||||
|
breakdown: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Payee {
|
pub struct Payee {
|
||||||
/// The email address of merchant.
|
/// The email address of merchant.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub email_address: Option<String>,
|
pub email_address: Option<String>,
|
||||||
/// The encrypted PayPal account ID of the merchant.
|
/// The encrypted PayPal account ID of the merchant.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub merchant_id: Option<String>,
|
pub merchant_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct PlatformFee {
|
pub struct PlatformFee {
|
||||||
pub amount: Money,
|
pub amount: Money,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payee: Option<Payee>,
|
pub payee: Option<Payee>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum DisbursementMode {
|
pub enum DisbursementMode {
|
||||||
/// The funds are released to the merchant immediately.
|
/// The funds are released to the merchant immediately.
|
||||||
Instant,
|
Instant,
|
||||||
|
@ -191,15 +232,18 @@ impl Default for DisbursementMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[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")]
|
||||||
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")]
|
||||||
pub disbursement_mode: Option<DisbursementMode>
|
pub disbursement_mode: Option<DisbursementMode>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[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
|
||||||
|
@ -215,13 +259,15 @@ impl Default for ItemCategoryType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct ShippingDetail {
|
pub struct ShippingDetail {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub address: Option<Address>,
|
pub address: Option<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
/// The item name or title.
|
/// The item name or title.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -229,21 +275,153 @@ pub struct Item {
|
||||||
/// 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")]
|
||||||
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")]
|
||||||
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")]
|
||||||
pub sku: Option<String>,
|
pub sku: Option<String>,
|
||||||
/// The item category type
|
/// The item category type
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub category: Option<ItemCategoryType>,
|
pub category: Option<ItemCategoryType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct PurchaseUnitRequest {
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum AuthorizationStatus {
|
||||||
|
/// The authorized payment is created. No captured payments have been made for this authorized payment.
|
||||||
|
Created,
|
||||||
|
/// The authorized payment has one or more captures against it. The sum of these captured payments is greater than the amount of the original authorized payment.
|
||||||
|
Captured,
|
||||||
|
/// PayPal cannot authorize funds for this authorized payment.
|
||||||
|
Denied,
|
||||||
|
/// The authorized payment has expired.
|
||||||
|
Expired,
|
||||||
|
/// A captured payment was made for the authorized payment for an amount that is less than the amount of the original authorized payment.
|
||||||
|
PartiallyExpired,
|
||||||
|
/// The payment which was authorized for an amount that is less than the originally requested amount.
|
||||||
|
PartiallyCaptured,
|
||||||
|
/// The authorized payment was voided. No more captured payments can be made against this authorized payment.
|
||||||
|
Voided,
|
||||||
|
/// The created authorization is in pending state. For more information, see status.details.
|
||||||
|
Pending,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum AuthorizationStatusDetails {
|
||||||
|
/// Authorization is pending manual review.
|
||||||
|
PendingReview,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct AuthorizationWithData {
|
||||||
|
/// The status for the authorized payment.
|
||||||
|
status: AuthorizationStatus,
|
||||||
|
/// The details of the authorized order pending status.
|
||||||
|
status_details: AuthorizationStatusDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum CaptureStatus {
|
||||||
|
/// The funds for this captured payment were credited to the payee's PayPal account.
|
||||||
|
Completed,
|
||||||
|
/// The funds could not be captured.
|
||||||
|
Declined,
|
||||||
|
/// An amount less than this captured payment's amount was partially refunded to the payer.
|
||||||
|
PartiallyRefunded,
|
||||||
|
/// The funds for this captured payment was not yet credited to the payee's PayPal account. For more information, see status.details.
|
||||||
|
Pending,
|
||||||
|
/// An amount greater than or equal to this captured payment's amount was refunded to the payer.
|
||||||
|
Refunded,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum CaptureStatusDetails {
|
||||||
|
/// The payer initiated a dispute for this captured payment with PayPal.
|
||||||
|
BuyerComplaint,
|
||||||
|
/// 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.
|
||||||
|
Chargeback,
|
||||||
|
/// The payer paid by an eCheck that has not yet cleared.
|
||||||
|
Echeck,
|
||||||
|
/// Visit your online account. In your **Account Overview**, accept and deny this payment.
|
||||||
|
InternationalWithdrawal,
|
||||||
|
/// No additional specific reason can be provided. For more information about this captured payment, visit your account online or contact PayPal.
|
||||||
|
Other,
|
||||||
|
/// The captured payment is pending manual review.
|
||||||
|
PendingReview,
|
||||||
|
/// 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.
|
||||||
|
/// 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.
|
||||||
|
ReceivingPreferenceMandatesManualAction,
|
||||||
|
/// The captured funds were refunded.
|
||||||
|
Refunded,
|
||||||
|
/// The payer must send the funds for this captured payment. This code generally appears for manual EFTs.
|
||||||
|
TransactionApprovedAwaitingFunding,
|
||||||
|
/// The payee does not have a PayPal account.
|
||||||
|
Unilateral,
|
||||||
|
/// The payee's PayPal account is not verified.
|
||||||
|
VerificationRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Capture {
|
||||||
|
/// The status of the captured payment.
|
||||||
|
status: CaptureStatus,
|
||||||
|
/// The details of the captured payment status.
|
||||||
|
status_details: CaptureStatusDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum RefundStatus {
|
||||||
|
/// The refund was cancelled.
|
||||||
|
Cancelled,
|
||||||
|
/// The refund is pending. For more information, see status_details.reason.
|
||||||
|
Pending,
|
||||||
|
/// The funds for this transaction were debited to the customer's account.
|
||||||
|
Completed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The reason why the refund has the PENDING or FAILED status.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum RefundStatusDetails {
|
||||||
|
/// The customer's account is funded through an eCheck, which has not yet cleared.
|
||||||
|
Echeck,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Refund {
|
||||||
|
/// The status of the refund.
|
||||||
|
status: RefundStatus,
|
||||||
|
/// The details of the refund status.
|
||||||
|
status_details: RefundStatusDetails,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PaymentCollection {
|
||||||
|
/// An array of authorized payments for a purchase unit. A purchase unit can have zero or more authorized payments.
|
||||||
|
authorizations: Vec<AuthorizationWithData>,
|
||||||
|
/// An array of captured payments for a purchase unit. A purchase unit can have zero or more captured payments.
|
||||||
|
captures: Vec<Capture>,
|
||||||
|
/// An array of refunds for a purchase unit. A purchase unit can have zero or more refunds.
|
||||||
|
refuns: Vec<Refund>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct PurchaseUnit {
|
||||||
/// The API caller-provided external ID for the purchase unit. Required for multiple purchase units when you must update the order through PATCH.
|
/// The API caller-provided external ID for the purchase unit. Required for multiple purchase units when you must update the order through PATCH.
|
||||||
/// If you omit this value and the order contains only one purchase unit, PayPal sets this value to default.
|
/// If you omit this value and the order contains only one purchase unit, PayPal sets this value to default.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub reference_id: Option<String>,
|
pub reference_id: Option<String>,
|
||||||
/// The total order amount with an optional breakdown that provides details, such as the total item amount,
|
/// The total order amount with an optional breakdown that provides details, such as the total item amount,
|
||||||
/// total tax amount, shipping, handling, insurance, and discounts, if any.
|
/// total tax amount, shipping, handling, insurance, and discounts, if any.
|
||||||
|
@ -254,31 +432,57 @@ pub struct PurchaseUnitRequest {
|
||||||
/// see the PayPal REST APIs [Currency Codes](https://developer.paypal.com/docs/integration/direct/rest/currency-codes/).
|
/// see the PayPal REST APIs [Currency Codes](https://developer.paypal.com/docs/integration/direct/rest/currency-codes/).
|
||||||
pub amount: Amount,
|
pub amount: Amount,
|
||||||
/// The merchant who receives payment for this transaction.
|
/// The merchant who receives payment for this transaction.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
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.
|
||||||
pub payment_instruction: Option<PaymentInstruction>,
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub payment_instruction: Option<PaymentInstruction>,
|
||||||
/// The purchase description.
|
/// The purchase description.
|
||||||
|
#[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")]
|
||||||
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")]
|
||||||
pub invoice_id: Option<String>,
|
pub invoice_id: Option<String>,
|
||||||
|
/// 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.
|
||||||
|
/// 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.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
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.
|
||||||
///
|
///
|
||||||
/// 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")]
|
||||||
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")]
|
||||||
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")]
|
||||||
pub shipping: Option<ShippingDetail>,
|
pub shipping: Option<ShippingDetail>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub payments: Option<PaymentCollection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PurchaseUnit {
|
||||||
|
pub fn new(amount: Amount) -> Self {
|
||||||
|
Self {
|
||||||
|
amount,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[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,
|
||||||
|
@ -298,7 +502,8 @@ impl Default for LandingPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shipping preference
|
/// The shipping preference
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[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.
|
||||||
GetFromFile,
|
GetFromFile,
|
||||||
|
@ -314,7 +519,8 @@ impl Default for ShippingPreference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[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
|
||||||
/// the final amount is not known when the checkout flow is initiated and you want to redirect the customer
|
/// the final amount is not known when the checkout flow is initiated and you want to redirect the customer
|
||||||
|
@ -332,7 +538,8 @@ impl Default for UserAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[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,
|
||||||
|
@ -348,45 +555,233 @@ impl Default for PayeePreferred {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct PaymentMethod {
|
pub struct PaymentMethod {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payer_selected: Option<String>,
|
pub payer_selected: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub payer_prefered: Option<PayeePreferred>,
|
pub payer_prefered: Option<PayeePreferred>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[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")]
|
||||||
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")]
|
||||||
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
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub landing_page: Option<LandingPage>,
|
pub landing_page: Option<LandingPage>,
|
||||||
/// The shipping preference
|
/// The shipping preference
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub shipping_preference: Option<ShippingPreference>,
|
pub shipping_preference: Option<ShippingPreference>,
|
||||||
/// Configures a Continue or Pay Now checkout flow.
|
/// Configures a Continue or Pay Now checkout flow.
|
||||||
|
#[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")]
|
||||||
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")]
|
||||||
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")]
|
||||||
pub cancel_url: Option<String>,
|
pub cancel_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
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")]
|
||||||
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<PurchaseUnitRequest>,
|
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")]
|
||||||
pub application_context: Option<ApplicationContext>,
|
pub application_context: Option<ApplicationContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OrderPayload {
|
||||||
|
pub fn new<S: Into<Vec<PurchaseUnit>>>(intent: Intent, purchase_units: S) -> Self {
|
||||||
|
Self {
|
||||||
|
intent,
|
||||||
|
purchase_units: purchase_units.into(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The card brand or network.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum CardBrand {
|
||||||
|
/// Visa card.
|
||||||
|
Visa,
|
||||||
|
/// Mastecard card.
|
||||||
|
Mastercard,
|
||||||
|
/// Discover card.
|
||||||
|
Discover,
|
||||||
|
/// American Express card.
|
||||||
|
Amex,
|
||||||
|
/// Solo debit card.
|
||||||
|
Solo,
|
||||||
|
/// Japan Credit Bureau card.
|
||||||
|
JCB,
|
||||||
|
/// Military Star card.
|
||||||
|
Star,
|
||||||
|
/// Delta Airlines card.
|
||||||
|
Delta,
|
||||||
|
/// Switch credit card.
|
||||||
|
Switch,
|
||||||
|
/// Maestro credit card.
|
||||||
|
Maestro,
|
||||||
|
/// Carte Bancaire (CB) credit card.
|
||||||
|
CbNationale,
|
||||||
|
/// Configoga credit card.
|
||||||
|
Configoga,
|
||||||
|
/// Confidis credit card.
|
||||||
|
Confidis,
|
||||||
|
/// Visa Electron credit card.
|
||||||
|
Electron,
|
||||||
|
/// Cetelem credit card.
|
||||||
|
Cetelem,
|
||||||
|
/// China union pay credit card.
|
||||||
|
ChinaUnionPay,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum CardType {
|
||||||
|
Credit,
|
||||||
|
Debit,
|
||||||
|
Prepaid,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct CardResponse {
|
||||||
|
/// The last digits of the payment card.
|
||||||
|
pub last_digits: String,
|
||||||
|
/// The card brand or network.
|
||||||
|
pub brand: CardBrand,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub card_type: CardType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct WalletResponse {
|
||||||
|
pub apple_pay: CardResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PaymentSourceResponse {
|
||||||
|
pub card: CardResponse,
|
||||||
|
pub wallet: WalletResponse,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum OrderStatus {
|
||||||
|
/// The order was created with the specified context.
|
||||||
|
Created,
|
||||||
|
/// The order was saved and persisted. The order status continues to be in progress until a capture
|
||||||
|
/// is made with final_capture = true for all purchase units within the order.
|
||||||
|
Saved,
|
||||||
|
/// The customer approved the payment through the PayPal wallet or another form of guest or unbranded payment. For example, a card, bank account, or so on.
|
||||||
|
Approved,
|
||||||
|
/// All purchase units in the order are voided.
|
||||||
|
Voided,
|
||||||
|
/// The payment was authorized or the authorized payment was captured for the order.
|
||||||
|
Completed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum LinkMethod {
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Delete,
|
||||||
|
Head,
|
||||||
|
Connect,
|
||||||
|
Options,
|
||||||
|
Patch
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct LinkDescription {
|
||||||
|
/// The complete target URL.
|
||||||
|
pub href: String,
|
||||||
|
/// The link relation type, which serves as an ID for a link that unambiguously describes the semantics of the link.
|
||||||
|
pub rel: String,
|
||||||
|
/// The HTTP method required to make the related call.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub method: Option<LinkMethod>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Order {
|
||||||
|
/// The date and time when the transaction occurred.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub create_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
|
/// The date and time when the transaction was last updated.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub update_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
|
/// The ID of the order.
|
||||||
|
pub id: String,
|
||||||
|
/// The payment source used to fund the payment.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub payment_source: Option<PaymentSourceResponse>,
|
||||||
|
/// The intent to either capture payment immediately or authorize a payment for an order after order creation.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub intent: Option<Intent>,
|
||||||
|
/// The customer who approves and pays for the order. The customer is also known as the payer.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub payer: Option<Payer>,
|
||||||
|
/// 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.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub purchase_units: Option<Vec<PurchaseUnit>>,
|
||||||
|
/// The order status.
|
||||||
|
pub status: OrderStatus,
|
||||||
|
/// An array of request-related HATEOAS links. To complete payer approval, use the approve link to redirect the payer.
|
||||||
|
pub links: Vec<LinkDescription>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::Client {
|
||||||
|
/// 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>> {
|
||||||
|
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?;
|
||||||
|
|
||||||
|
if res.status().is_success() {
|
||||||
|
let order: Order = res.json::<Order>().await?;
|
||||||
|
Ok(order)
|
||||||
|
} else {
|
||||||
|
Err(Box::new(errors::Errors::ApiCallFailure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates an order with the CREATED or APPROVED 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
|
||||||
|
pub async fn update_order<S: AsRef<str>>(&self, id: S, status: S) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_order<S: AsRef<str>>(id: S) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Finish order https://developer.paypal.com/docs/api/orders/v2/
|
// TODO: Finish order https://developer.paypal.com/docs/api/orders/v2/
|
||||||
|
|
26
src/tests.rs
26
src/tests.rs
|
@ -1,19 +1,29 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use dotenv::dotenv;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn it_works() {
|
async fn it_works() {
|
||||||
dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
let clientid = env::var("PAYPAL_CLIENTID").unwrap();
|
let clientid = env::var("PAYPAL_CLIENTID").unwrap();
|
||||||
let secret = env::var("PAYPAL_SECRET").unwrap();
|
let secret = env::var("PAYPAL_SECRET").unwrap();
|
||||||
|
|
||||||
let mut client = Client::new(
|
let mut client = Client::new(clientid.as_str(), secret.as_str(), true);
|
||||||
clientid.as_str(),
|
|
||||||
secret.as_str(),
|
assert_eq!(
|
||||||
true,
|
client.get_access_token().await.is_err(),
|
||||||
|
false,
|
||||||
|
"should not error"
|
||||||
|
);
|
||||||
|
println!("{:#?}", client);
|
||||||
|
|
||||||
|
let order = orders::OrderPayload::new(
|
||||||
|
orders::Intent::Capture,
|
||||||
|
vec![orders::PurchaseUnit::new(orders::Amount::new(
|
||||||
|
"EUR", "10.0",
|
||||||
|
))],
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(client.get_access_token().await.is_err(), false, "should not error");
|
let order_created = client.create_order(order, HeaderParams::default()).await.unwrap();
|
||||||
println!("{:#?}", client);
|
|
||||||
|
println!("{:#?}", order_created);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue