start adding integration tests, derive builder in more places

This commit is contained in:
Edgar 2022-09-28 17:48:00 +02:00
parent 2b23f6a8db
commit 557113084b
No known key found for this signature in database
10 changed files with 407 additions and 43 deletions

View file

@ -28,7 +28,6 @@ serde_qs = "0.10.1"
[dev-dependencies] [dev-dependencies]
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
dotenv = "0.15.0" dotenv = "0.15.0"
anyhow = "1.0.65"
color-eyre = "0.6.2" color-eyre = "0.6.2"
wiremock = "0.5.14" wiremock = "0.5.14"

View file

@ -407,7 +407,7 @@ mod tests {
} }
#[tokio::test] #[tokio::test]
async fn test_invoice_create_cancel() -> anyhow::Result<()> { async fn test_invoice_create_cancel() -> color_eyre::Result<()> {
let client = create_client().await; let client = create_client().await;
let payload = InvoicePayloadBuilder::default() let payload = InvoicePayloadBuilder::default()

View file

@ -193,7 +193,7 @@ mod tests {
use crate::{api::orders::*, data::orders::*, tests::create_client}; use crate::{api::orders::*, data::orders::*, tests::create_client};
#[tokio::test] #[tokio::test]
async fn test_order() -> anyhow::Result<()> { async fn test_order() -> color_eyre::Result<()> {
let mut client = create_client().await; let mut client = create_client().await;
client.get_access_token().await.expect("get access token error"); client.get_access_token().await.expect("get access token error");

View file

@ -171,7 +171,7 @@ impl Client {
Ok(builder.headers(headers)) Ok(builder.headers(headers))
} }
/// Gets a access token used in all the api calls. /// Gets a access token used in all the api calls and saves it.
pub async fn get_access_token(&mut self) -> Result<(), ResponseError> { pub async fn get_access_token(&mut self) -> Result<(), ResponseError> {
if !self.access_token_expired() { if !self.access_token_expired() {
return Ok(()); return Ok(());

View file

@ -41,7 +41,8 @@ pub struct AddressDetails {
/// The address of the payer. /// The address of the payer.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into), default)]
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.
@ -63,6 +64,7 @@ pub struct Address {
/// Represents money /// Represents money
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Builder)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Builder)]
#[builder(setter(strip_option, into))]
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: Currency, pub currency_code: Currency,

View file

@ -1,6 +1,6 @@
//! Paypal object definitions used by the orders api. //! Paypal object definitions used by the orders api.
use super::common::*; use super::{common::*, invoice::BillingInfo};
use derive_builder::Builder; use derive_builder::Builder;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none; use serde_with::skip_serializing_none;
@ -28,7 +28,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, Eq, PartialEq, Clone)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Builder)]
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,
@ -38,7 +38,8 @@ pub struct PayerName {
} }
/// The phone number, in its canonical international E.164 numbering plan format. /// The phone number, in its canonical international E.164 numbering plan format.
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Builder)]
#[builder(setter(strip_option))]
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.
@ -49,7 +50,8 @@ 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.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct Phone { pub struct Phone {
/// The phone type. /// The phone type.
pub phone_type: Option<PhoneType>, pub phone_type: Option<PhoneType>,
@ -69,7 +71,8 @@ pub enum TaxIdType {
} }
/// The tax information of the payer. /// The tax information of the payer.
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
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.
@ -83,6 +86,7 @@ pub struct TaxInfo {
/// <https://developer.paypal.com/docs/api/orders/v2/#definition-payer> /// <https://developer.paypal.com/docs/api/orders/v2/#definition-payer>
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option), default)]
pub struct Payer { pub struct Payer {
/// The name of the payer. /// The name of the payer.
pub name: Option<PayerName>, pub name: Option<PayerName>,
@ -103,7 +107,8 @@ pub struct Payer {
/// 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.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into))]
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.
@ -124,7 +129,8 @@ pub struct Breakdown {
/// Represents an amount of money. /// Represents an amount of money.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
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: Currency, pub currency_code: Currency,
@ -147,11 +153,30 @@ impl Amount {
breakdown: None, breakdown: None,
} }
} }
/// Creates a new amount with the EUR currency.
pub fn eur(value: &str) -> Self {
Amount {
currency_code: Currency::EUR,
value: value.to_owned(),
breakdown: None,
}
}
/// Creates a new amount with the USD currency.
pub fn usd(value: &str) -> Self {
Amount {
currency_code: Currency::USD,
value: value.to_owned(),
breakdown: None,
}
}
} }
/// The merchant who receives payment for this transaction. /// The merchant who receives payment for this transaction.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into))]
pub struct Payee { pub struct Payee {
/// The email address of merchant. /// The email address of merchant.
pub email_address: Option<String>, pub email_address: Option<String>,
@ -161,7 +186,8 @@ pub struct Payee {
/// Fees, commissions, tips, or donations /// Fees, commissions, tips, or donations
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct PlatformFee { pub struct PlatformFee {
/// The fee for this transaction. /// The fee for this transaction.
pub amount: Money, pub amount: Money,
@ -189,7 +215,8 @@ impl Default for DisbursementMode {
/// Any additional payment instructions for PayPal Commerce Platform customers. /// Any additional payment instructions for PayPal Commerce Platform customers.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into))]
pub struct PaymentInstruction { pub struct PaymentInstruction {
/// An array of various fees, commissions, tips, or donations. /// An array of various fees, commissions, tips, or donations.
pub platform_fees: Option<Vec<PlatformFee>>, pub platform_fees: Option<Vec<PlatformFee>>,
@ -225,7 +252,8 @@ pub struct ShippingDetailName {
/// 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.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct ShippingDetail { pub struct ShippingDetail {
/// The name of the person to whom to ship the items. Supports only the full_name property. /// The name of the person to whom to ship the items. Supports only the full_name property.
pub name: Option<ShippingDetailName>, pub name: Option<ShippingDetailName>,
@ -235,7 +263,8 @@ pub struct ShippingDetail {
/// Represents an item. /// Represents an item.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into))]
pub struct Item { pub struct Item {
/// The item name or title. /// The item name or title.
pub name: String, pub name: String,
@ -342,7 +371,8 @@ pub struct CaptureStatusDetails {
/// A captured payment. /// A captured payment.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct Capture { pub struct Capture {
/// The status of the captured payment. /// The status of the captured payment.
pub status: CaptureStatus, pub status: CaptureStatus,
@ -378,7 +408,7 @@ pub struct RefundStatusDetails {
} }
/// Exchange rate. /// Exchange rate.
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
pub struct ExchangeRate { pub struct ExchangeRate {
/// The source currency from which to convert an amount. /// The source currency from which to convert an amount.
pub source_currency: Currency, pub source_currency: Currency,
@ -389,7 +419,7 @@ pub struct ExchangeRate {
} }
/// The net breakdown of the refund. /// The net breakdown of the refund.
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
pub struct NetAmountBreakdown { pub struct NetAmountBreakdown {
/// The converted payable amount. /// The converted payable amount.
pub converted_amount: Money, pub converted_amount: Money,
@ -400,7 +430,8 @@ pub struct NetAmountBreakdown {
} }
/// The breakdown of the refund. /// The breakdown of the refund.
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct SellerPayableBreakdown { pub struct SellerPayableBreakdown {
/// The amount that the payee refunded to the payer. /// The amount that the payee refunded to the payer.
pub gross_amount: Money, pub gross_amount: Money,
@ -421,7 +452,8 @@ pub struct SellerPayableBreakdown {
} }
/// A refund /// A refund
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct Refund { pub struct Refund {
/// The status of the refund. /// The status of the refund.
pub status: RefundStatus, pub status: RefundStatus,
@ -442,7 +474,8 @@ pub struct Refund {
} }
/// The comprehensive history of payments for the purchase unit. /// The comprehensive history of payments for the purchase unit.
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
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.
#[serde(default)] #[serde(default)]
@ -457,7 +490,8 @@ pub struct PaymentCollection {
/// Represents either a full or partial order that the payer intends to purchase from the payee. /// Represents either a full or partial order that the payer intends to purchase from the payee.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into), default)]
pub struct PurchaseUnit { 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.
@ -600,7 +634,8 @@ pub struct PaymentMethod {
/// 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.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into), default)]
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.
pub brand_name: Option<String>, pub brand_name: Option<String>,
@ -622,31 +657,81 @@ pub struct ApplicationContext {
pub cancel_url: Option<String>, pub cancel_url: Option<String>,
} }
/// A order payload to be used when creating an order. /// A card used in payment sources.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)] #[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option), default)] #[builder(setter(into))]
pub struct PaymentCard {
/// The card number.
pub number: String,
/// The expiry date.
pub expiry: String,
/// The card owner name.
pub name: String,
/// The billing address.
pub billing_address: Address
}
/// A transaction reference.
#[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(into))]
pub struct TransactionReference {
/// The transaction id.
pub id: String,
/// The transaction network, e.g "VISA"
pub network: String,
}
/// A stored credential.
#[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(into))]
pub struct StoredCredential {
/// The payment initiator, e.g "MERCHANT"
pub payment_initiator: String,
/// The payment type, e.g "RECURRING"
pub payment_type: String,
/// The stored credential usage, e.g: SUBSEQUENT
pub usage: String,
/// The billing address.
pub previous_network_transaction_reference: TransactionReference
}
/// A order payload to be used when creating an order.
// TODO: this only appears in the example body, not documented.
// https://developer.paypal.com/docs/api/orders/v2/#orders_create
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct OrderPaymentSource {
/// The card used in the payment.
pub card: PaymentCard,
/// A stored credential.
// TODO: figure out what is this.
#[builder(default)]
pub stored_credential: Option<StoredCredential>,
}
/// A order payload to be used when creating an order.
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
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. /// DEPRECATED. The customer who approves and pays for the order. The customer is also known as the payer.
#[builder(default)]
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.
#[builder(default)]
pub application_context: Option<ApplicationContext>, pub application_context: Option<ApplicationContext>,
} /// The payment source.
#[builder(default)]
impl OrderPayload { pub payment_source: Option<OrderPaymentSource>,
/// Creates a new order payload with the required properties.
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. /// The card brand or network.
@ -717,7 +802,7 @@ pub struct WalletResponse {
} }
/// The paypal account used to fund the transaction. /// The paypal account used to fund the transaction.
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
pub struct PaypalPaymentSourceResponse { pub struct PaypalPaymentSourceResponse {
/// The name of the payer. /// The name of the payer.
pub name: PayerName, pub name: PayerName,
@ -728,7 +813,8 @@ pub struct PaypalPaymentSourceResponse {
} }
/// The payment source used to fund the payment. /// The payment source used to fund the payment.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Builder, Default, Clone)]
#[builder(setter(strip_option), default)]
pub struct PaymentSourceResponse { pub struct PaymentSourceResponse {
/// The payment card to use to fund a payment. Card can be a credit or debit card /// The payment card to use to fund a payment. Card can be a credit or debit card
pub card: Option<CardResponse>, pub card: Option<CardResponse>,
@ -740,7 +826,7 @@ pub struct PaymentSourceResponse {
} }
/// The status of an order. /// The status of an order.
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Copy)]
#[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.
@ -758,7 +844,8 @@ pub enum OrderStatus {
/// An order represents a payment between two or more parties. /// An order represents a payment between two or more parties.
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct Order { pub struct Order {
/// The date and time when the transaction occurred. /// The date and time when the transaction occurred.
pub create_time: Option<chrono::DateTime<chrono::Utc>>, pub create_time: Option<chrono::DateTime<chrono::Utc>>,

36
tests/auth_tests.rs Normal file
View file

@ -0,0 +1,36 @@
use paypal_rs::{api::orders::*, data::orders::*};
use paypal_rs::{data::common::Currency, Client, PaypalEnv};
use paypal_rs::{AccessToken, HeaderParams};
use wiremock::matchers::{basic_auth, body_string, header, method, path, BodyExactMatcher, HeaderExactMatcher};
use wiremock::{
matchers::{BasicAuthMatcher, BearerTokenMatcher},
Mock, MockServer, ResponseTemplate,
};
fn create_client(url: &str) -> Client {
Client::new("clientid".to_string(), "secret".to_string(), PaypalEnv::Mock(url.to_string()))
}
#[tokio::test]
async fn test_auth() -> color_eyre::Result<()> {
color_eyre::install()?;
let mock_server = MockServer::start().await;
let access_token: serde_json::Value = serde_json::from_str(include_str!("resources/oauth_token.json")).unwrap();
Mock::given(method("POST"))
.and(path("/v1/oauth2/token"))
.and(basic_auth("clientid", "secret"))
.and(header("Content-Type", "x-www-form-urlencoded"))
.and(body_string("grant_type=client_credentials"))
.respond_with(ResponseTemplate::new(200).set_body_json(&access_token))
.mount(&mock_server)
.await;
let mut client = create_client(&mock_server.uri());
client.get_access_token().await?;
Ok(())
}

165
tests/orders_tests.rs Normal file
View file

@ -0,0 +1,165 @@
use paypal_rs::{
api::orders::*,
data::{common::AddressBuilder, orders::*},
};
use paypal_rs::{Client, PaypalEnv};
use wiremock::matchers::{basic_auth, bearer_token, body_string, header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
fn create_client(url: &str) -> Client {
Client::new(
"clientid".to_string(),
"secret".to_string(),
PaypalEnv::Mock(url.to_string()),
)
}
#[tokio::test]
async fn test_create_order() -> color_eyre::Result<()> {
color_eyre::install()?;
let mock_server = MockServer::start().await;
let access_token: serde_json::Value = serde_json::from_str(include_str!("resources/oauth_token.json")).unwrap();
Mock::given(method("POST"))
.and(path("/v1/oauth2/token"))
.and(basic_auth("clientid", "secret"))
.and(header("Content-Type", "x-www-form-urlencoded"))
.and(body_string("grant_type=client_credentials"))
.respond_with(ResponseTemplate::new(200).set_body_json(&access_token))
.mount(&mock_server)
.await;
let response_body: serde_json::Value =
serde_json::from_str(include_str!("resources/create_order_response.json")).unwrap();
Mock::given(method("POST"))
.and(path("/v2/checkout/orders"))
.and(bearer_token("TESTBEARERTOKEN"))
.and(header("Content-Type", "application/json"))
.respond_with(ResponseTemplate::new(200).set_body_json(&response_body))
.mount(&mock_server)
.await;
let mut client = create_client(&mock_server.uri());
client.get_access_token().await?;
let order = OrderPayloadBuilder::default()
.intent(Intent::Authorize)
.purchase_units(vec![PurchaseUnitBuilder::default()
.reference_id("d9f80740-38f0-11e8-b467-0ed5f89f718b")
.amount(Amount::usd("100.00"))
.build()?])
.payment_source(
OrderPaymentSourceBuilder::default()
.card(
PaymentCardBuilder::default()
.number("4111111111111111")
.expiry("2020-02")
.name("John Doe")
.billing_address(
AddressBuilder::default()
.address_line_1("2211 N First Street")
.address_line_2("17.3.160")
.admin_area_1("CA")
.admin_area_2("San Jose")
.postal_code("95131")
.country_code("US")
.build()?,
)
.build()?,
)
.stored_credential(
StoredCredentialBuilder::default()
.payment_initiator("MERCHANT")
.payment_type("RECURRING")
.usage("SUBSEQUENT")
.previous_network_transaction_reference(
TransactionReferenceBuilder::default()
.id("156GHJ654SFH543")
.network("VISA")
.build()?,
)
.build()?,
)
.build()?,
)
.build()?;
let create_order = CreateOrder::new(order);
Ok(())
}
/*
#[tokio::test]
async fn test_order2() -> anyhow::Result<()> {
let mock_server = MockServer::start().await;
let mut client = create_client(&mock_server.uri());
client.get_access_token().await?;
let order = OrderPayloadBuilder::default()
.intent(Intent::Authorize)
.purchase_units(vec![PurchaseUnit::new(Amount::new(Currency::EUR, "10.0"))])
.build()?;
let ref_id = format!(
"TEST-{:?}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
);
let create_order = CreateOrder::new(order);
let order_created = client
.execute_ext(
&create_order,
HeaderParams {
request_id: Some(ref_id.clone()),
..Default::default()
},
)
.await;
assert!(order_created.is_ok());
let order_created = order_created?;
assert_ne!(order_created.id, "");
assert_eq!(order_created.status, OrderStatus::Created);
assert_eq!(order_created.links.len(), 4);
let show_order = ShowOrderDetails::new(&order_created.id);
let show_order_result = client
.execute_ext(
&show_order,
HeaderParams {
request_id: Some(ref_id.clone()),
..Default::default()
},
)
.await;
assert!(show_order_result.is_ok());
let show_order_result = show_order_result?;
assert_eq!(order_created.id, show_order_result.id);
assert_eq!(order_created.status, show_order_result.status);
let authorize_order = AuthorizeOrder::new(&show_order_result.id);
let res = client.execute(&authorize_order).await;
assert!(res.is_err()); // Fails with ORDER_NOT_APPROVED
Ok(())
} */

View file

@ -0,0 +1,67 @@
{
"id": "5O190127TN364715T",
"status": "COMPLETED",
"payment_source": {
"card": {
"last_digits": "1111",
"brand": "VISA",
"type": "CREDIT"
}
},
"purchase_units": [
{
"reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b",
"payments": {
"authorizations": [
{
"id": "0AW2184448108334S",
"status": "CREATED",
"amount": {
"currency_code": "USD",
"value": "100.00"
},
"seller_protection": {
"status": "NOT_ELIGIBLE"
},
"processor_response": {
"avs_code": "Z",
"response_code": "0000"
},
"expiration_time": "2022-04-01T21:20:49Z",
"create_time": "2022-03-01T21:20:49Z",
"update_time": "2022-03-01T21:20:49Z",
"links": [
{
"href": "https://api-m.paypal.com/v2/payments/authorizations/0AW2184448108334S",
"rel": "self",
"method": "GET"
},
{
"href": "https://api-m.paypal.com/v2/payments/authorizations/0AW2184448108334S/capture",
"rel": "capture",
"method": "POST"
},
{
"href": "https://api-m.paypal.com/v2/payments/authorizations/0AW2184448108334S/void",
"rel": "void",
"method": "POST"
},
{
"href": "https://api-m.paypal.com/v2/payments/authorizations/0AW2184448108334S/reauthorize",
"rel": "reauthorize",
"method": "POST"
}
]
}
]
}
}
],
"links": [
{
"href": "https://api-m.paypal.com/v2/checkout/orders/5O190127TN364715T",
"rel": "self",
"method": "GET"
}
]
}

View file

@ -0,0 +1,8 @@
{
"scope": "https://uri.paypal.com/services/invoicing https://uri.paypal.com/services/disputes/read-buyer https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/disputes/update-seller https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/disputes/read-seller https://uri.paypal.com/services/payments/refund https://api-m.paypal.com/v1/vault/credit-card https://api-m.paypal.com/v1/payments/.* https://uri.paypal.com/payments/payouts https://api-m.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/subscriptions https://uri.paypal.com/services/applications/webhooks",
"access_token": "TESTBEARERTOKEN",
"token_type": "Bearer",
"app_id": "APP-80W284485P519543T",
"expires_in": 9999999,
"nonce": "2022-08-03T15:35:36ZaYZlGvEkV4yVSz8g6bAKFoGSEzuy3CQcz3ljhibkOHg"
}