added more invoice methods

This commit is contained in:
Edgar 2020-08-12 17:43:59 +02:00
parent b125e95e43
commit 7be2b4ce2c
No known key found for this signature in database
GPG key ID: 8731E6C0166EAA85
2 changed files with 184 additions and 37 deletions

View file

@ -22,3 +22,4 @@ 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"] }
bytes = "0.5"

View file

@ -9,7 +9,8 @@
use crate::common::*; use crate::common::*;
use crate::errors; use crate::errors;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::{collections::HashMap};
use bytes::Bytes;
/// Paypal File reference /// Paypal File reference
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -652,9 +653,48 @@ pub struct InvoiceList {
/// Total pages /// Total pages
pub total_pages: i32, pub total_pages: i32,
/// The invoices /// The invoices
items: Vec<Invoice>, pub items: Vec<Invoice>,
/// HATEOAS links /// HATEOAS links
links: Vec<LinkDescription>, pub links: Vec<LinkDescription>,
}
/// Cancel invoice reason
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct CancelReason {
/// The subject of the email that is sent as a notification to the recipient.
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
/// A note to the payer.
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
/// Indicates whether to send a copy of the email to the merchant.
#[serde(skip_serializing_if = "Option::is_none")]
pub send_to_invoicer: Option<bool>,
/// Indicates whether to send a copy of the email to the recipient.
#[serde(skip_serializing_if = "Option::is_none")]
pub send_to_recipient: Option<bool>,
/// An array of one or more CC: emails to which notifications are sent.
/// If you omit this parameter, a notification is sent to all CC: email addresses that are part of the invoice.
#[serde(skip_serializing_if = "Option::is_none")]
pub additional_recipients: Option<Vec<String>>,
}
/// QR pay action
pub const QR_ACTION_PAY: &str = "pay";
/// QR details action
pub const QR_ACTION_DETAILS: &str ="details";
/// QR creation parameters
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct QRCodeParams {
/// The width, in pixels, of the QR code image. Value is from 150 to 500.
pub width: i32,
/// The height, in pixels, of the QR code image. Value is from 150 to 500.
pub height: i32,
/// The type of URL for which to generate a QR code. Valid values are pay and details.
///
/// Check QR_ACTION_PAY and QR_ACTION_DETAILS constants
pub action: Option<String>,
} }
impl super::Client { impl super::Client {
@ -728,7 +768,7 @@ impl super::Client {
} }
} }
/// Get an invoice by ID. /// List invoices
/// Page size has the following limits: [1, 100]. /// Page size has the following limits: [1, 100].
pub async fn list_invoices( pub async fn list_invoices(
&self, &self,
@ -737,8 +777,15 @@ impl super::Client {
page_size: i32, page_size: i32,
) -> Result<InvoiceList, Box<dyn std::error::Error>> { ) -> Result<InvoiceList, Box<dyn std::error::Error>> {
let build = self.setup_headers( let build = self.setup_headers(
self.client self.client.get(
.get(format!("{}/v2/invoicing/invoices?page={}&page_size={}&total_required=true", self.endpoint(), page, page_size).as_str()), format!(
"{}/v2/invoicing/invoices?page={}&page_size={}&total_required=true",
self.endpoint(),
page,
page_size
)
.as_str(),
),
header_params, header_params,
); );
@ -751,4 +798,103 @@ impl super::Client {
Err(Box::new(res.json::<errors::ApiResponseError>().await?)) Err(Box::new(res.json::<errors::ApiResponseError>().await?))
} }
} }
/// Delete a invoice
pub async fn delete_invoice<S: std::fmt::Display>(
&self,
header_params: crate::HeaderParams,
invoice_id: S,
) -> Result<(), Box<dyn std::error::Error>> {
let build = self.setup_headers(
self.client
.delete(format!("{}/v2/invoicing/invoices/{}", self.endpoint(), invoice_id).as_str()),
header_params,
);
let res = build.send().await?;
if res.status().is_success() {
Ok(())
} else {
Err(Box::new(res.json::<errors::ApiResponseError>().await?))
}
}
/// Update a invoice
pub async fn update_invoice(
&self,
header_params: crate::HeaderParams,
invoice: Invoice,
send_to_recipient: bool,
send_to_invoicer: bool,
) -> Result<(), Box<dyn std::error::Error>> {
let build = self.setup_headers(
self.client.put(
format!(
"{}/v2/invoicing/invoices/{}?send_to_recipient={}&send_to_invoicer={}",
self.endpoint(),
invoice.id,
send_to_recipient,
send_to_invoicer
)
.as_str(),
),
header_params,
);
let res = build.send().await?;
if res.status().is_success() {
Ok(())
} else {
Err(Box::new(res.json::<errors::ApiResponseError>().await?))
}
}
/// Cancel a invoice
pub async fn cancel_invoice<S: std::fmt::Display>(
&self,
header_params: crate::HeaderParams,
invoice_id: S,
reason: CancelReason,
) -> Result<(), Box<dyn std::error::Error>> {
let build = self.setup_headers(
self.client
.post(format!("{}/v2/invoicing/invoices/{}/cancel", self.endpoint(), invoice_id,).as_str()),
header_params,
);
let res = build.json(&reason).send().await?;
if res.status().is_success() {
Ok(())
} else {
Err(Box::new(res.json::<errors::ApiResponseError>().await?))
}
}
/// Generate a QR code
pub async fn generate_qr_code<S: std::fmt::Display>(
&self,
header_params: crate::HeaderParams,
invoice_id: S,
params: QRCodeParams,
) -> Result<Bytes, Box<dyn std::error::Error>> {
let build = self.setup_headers(
self.client
.post(format!("{}/v2/invoicing/invoices/{}/generate-qr-code", self.endpoint(), invoice_id).as_str()),
header_params,
);
let res = build.json(&params).send().await?;
if res.status().is_success() {
let b = res.bytes().await?;
Ok(b)
} else {
Err(Box::new(res.json::<errors::ApiResponseError>().await?))
}
}
// TODO: https://developer.paypal.com/docs/api/invoicing/v2/#invoices_payments
} }