diff --git a/Cargo.toml b/Cargo.toml index c269a33..e5e1594 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,19 +14,19 @@ edition = "2021" [dependencies] reqwest = { version = "0.11.10", default-features = false, features = ["json"] } -serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" +serde = { version = "1.0.137", features = ["derive"] } +serde_json = "1.0.81" serde_with = "1.13.0" chrono = { version = "0.4.19", features = ["serde"] } jsonwebtoken = "8.1.0" base64 = "0.13.0" -log = "0.4.16" +log = "0.4.17" bytes = "1.1.0" derive_builder = "0.11.2" -serde_qs = "0.9.1" +serde_qs = "0.9.2" [dev-dependencies] -tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.18.2", features = ["macros", "rt-multi-thread"] } dotenv = "0.15.0" anyhow = "1.0.57" color-eyre = "0.6.1" diff --git a/src/api/invoice.rs b/src/api/invoice.rs index 197c696..61e0616 100644 --- a/src/api/invoice.rs +++ b/src/api/invoice.rs @@ -102,8 +102,8 @@ pub struct GetInvoice { impl GetInvoice { /// New constructor. - pub fn new(invoice_id: String) -> Self { - Self { invoice_id } + pub fn new(invoice_id: impl ToString) -> Self { + Self { invoice_id: invoice_id.to_string() } } } @@ -171,8 +171,8 @@ pub struct DeleteInvoice { impl DeleteInvoice { /// New constructor. - pub fn new(invoice_id: String) -> Self { - Self { invoice_id } + pub fn new(invoice_id: impl ToString) -> Self { + Self { invoice_id: invoice_id.to_string() } } } @@ -254,8 +254,8 @@ pub struct CancelInvoice { impl CancelInvoice { /// New constructor. - pub fn new(invoice_id: String, reason: CancelReason) -> Self { - Self { invoice_id, reason } + pub fn new(invoice_id: impl ToString, reason: CancelReason) -> Self { + Self { invoice_id: invoice_id.to_string(), reason } } } diff --git a/src/api/mod.rs b/src/api/mod.rs index 28c803f..dff5ee0 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -2,3 +2,4 @@ pub mod invoice; pub mod orders; +pub mod payments; diff --git a/src/api/payments.rs b/src/api/payments.rs new file mode 100644 index 0000000..55d070e --- /dev/null +++ b/src/api/payments.rs @@ -0,0 +1,49 @@ +//! Call the Payments API to authorize payments, capture authorized payments, refund payments that have already been captured, and show payment information. +//! +//! Reference: https://developer.paypal.com/docs/api/payments/v2/ + +use std::borrow::Cow; + +use derive_builder::Builder; + +use crate::{data::payment::*, endpoint::Endpoint}; + +/// Generates the next invoice number that is available to the merchant. +/// +/// The next invoice number uses the prefix and suffix from the last invoice number and increments the number by one. +/// +/// For example, the next invoice number after `INVOICE-1234` is `INVOICE-1235`. +#[derive(Debug, Default, Clone, Builder)] +pub struct GetAuthorizedPayment { + /// The ID of the authorized payment for which to show details. + pub authorization_id: String, +} + +impl GetAuthorizedPayment { + /// New constructor. + pub fn new(authorization_id: impl ToString) -> Self { + Self { + authorization_id: authorization_id.to_string(), + } + } +} + +impl Endpoint for GetAuthorizedPayment { + type Query = (); + + type Body = (); + + type Response = AuthorizedPaymentDetails; + + fn relative_path(&self) -> Cow { + Cow::Owned(format!("/v2/payments/authorizations/{}", self.authorization_id)) + } + + fn method(&self) -> reqwest::Method { + reqwest::Method::GET + } + + fn body(&self) -> Option<&Self::Body> { + None + } +} diff --git a/src/data/common.rs b/src/data/common.rs index bcda40d..a1e33c7 100644 --- a/src/data/common.rs +++ b/src/data/common.rs @@ -111,7 +111,7 @@ pub enum LinkMethod { /// A HTOAES link #[skip_serializing_none] -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct LinkDescription { /// The complete target URL. pub href: String, @@ -223,3 +223,49 @@ impl FromStr for Currency { } } } + +/// Details about the status of the authorization. +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] +pub struct AuthorizationStatusDetails { + /// The reason why the authorized status is PENDING. + pub reason: AuthorizationStatusDetailsReason, +} + +/// Authorization status reason. +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum AuthorizationStatusDetailsReason { + /// Authorization is pending manual review. + PendingReview, +} + +/// Indicates whether the transaction is eligible for seller protection. +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum SellerProtectionStatus { + /// Your PayPal balance remains intact if the customer claims that they did not receive an item or the account holder claims that they did not authorize the payment. + Eligible, + /// Your PayPal balance remains intact if the customer claims that they did not receive an item. + PartiallyEligible, + /// This transaction is not eligible for seller protection. + NotEligible, +} + +/// The condition that is covered for the transaction. +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum DisputeCategory { + /// The payer paid for an item that they did not receive. + ItemNotReceived, + /// The payer did not authorize the payment. + UnauthorizedTransaction, +} + +/// The level of protection offered as defined by PayPal Seller Protection for Merchants. +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct SellerProtection { + /// Indicates whether the transaction is eligible for seller protection. + pub status: SellerProtectionStatus, + /// An array of conditions that are covered for the transaction. + pub dispute_categories: Vec, +} \ No newline at end of file diff --git a/src/data/mod.rs b/src/data/mod.rs index bd1df39..314e90a 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -3,3 +3,4 @@ pub mod common; pub mod invoice; pub mod orders; +pub mod payment; diff --git a/src/data/orders.rs b/src/data/orders.rs index 8c88a4d..30350f4 100644 --- a/src/data/orders.rs +++ b/src/data/orders.rs @@ -268,21 +268,6 @@ pub enum AuthorizationStatus { Pending, } -/// Authorization status reason. -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] -pub enum AuthorizationStatusDetailsReason { - /// Authorization is pending manual review. - PendingReview, -} - -/// Details about the status of the authorization. -#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] -pub struct AuthorizationStatusDetails { - /// The reason why the authorized status is PENDING. - pub reason: AuthorizationStatusDetailsReason, -} - /// A payment authorization. #[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)] pub struct AuthorizationWithData { diff --git a/src/data/payment.rs b/src/data/payment.rs new file mode 100644 index 0000000..2ebe6e1 --- /dev/null +++ b/src/data/payment.rs @@ -0,0 +1,55 @@ +//! Paypal object definitions used by the payments api. + +use serde::{Deserialize, Serialize}; + +use super::common::{AuthorizationStatusDetails, Money, SellerProtection, LinkDescription}; + + +/// Payment Status +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Copy)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PaymentStatus { + /// 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. + PartiallyCaptured, + /// The payment which was authorized for an amount that is less than the originally requested amount. + PartiallyCreated, + /// The authorized payment was voided. No more captured payments can be made against this authorized payment. + Voided, + /// The created authorization is in pending state. + Pending, +} + +/// The authorized payment details. +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct AuthorizedPaymentDetails { + /// The status for the authorized payment. + pub status: PaymentStatus, + /// The details of the authorized order pending status. + pub status_details: AuthorizationStatusDetails, + /// The PayPal-generated ID for the authorized payment. + pub id: String, + /// The amount for this authorized payment. + pub amount: Money, + /// 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. + pub invoice_id: String, + /// The API caller-provided external ID. Used to reconcile API caller-initiated transactions with PayPal transactions. Appears in transaction and settlement reports. + pub custom_id: String, + /// The level of protection offered as defined by PayPal Seller Protection for Merchants. + pub seller_protection: SellerProtection, + /// The date and time when the authorized payment expires + pub expiration_time: chrono::DateTime, + /// An array of related HATEOAS links. + pub links: Vec, + /// The date and time when the transaction occurred + pub create_time: chrono::DateTime, + /// The date and time when the transaction was last updated + pub update_time: chrono::DateTime, +} \ No newline at end of file