start adding integration tests, derive builder in more places
This commit is contained in:
parent
2b23f6a8db
commit
557113084b
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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(());
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
36
tests/auth_tests.rs
Normal 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
165
tests/orders_tests.rs
Normal 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(())
|
||||||
|
} */
|
67
tests/resources/create_order_response.json
Normal file
67
tests/resources/create_order_response.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
8
tests/resources/oauth_token.json
Normal file
8
tests/resources/oauth_token.json
Normal 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"
|
||||||
|
}
|
Loading…
Reference in a new issue