add typed currency

This commit is contained in:
Edgar 2021-01-05 13:40:36 +01:00
parent a2032510e3
commit 6a186d0025
No known key found for this signature in database
GPG key ID: 8731E6C0166EAA85
6 changed files with 140 additions and 11 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "paypal-rs"
version = "0.2.0-alpha.1"
version = "0.2.0-alpha.2"
authors = ["Edgar <git@edgarluque.com>"]
description = "A library that wraps the paypal api asynchronously."
repository = "https://github.com/edg-l/paypal-rs/"

View file

@ -3,7 +3,7 @@
![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 in a strongly typed manner.
A rust library that wraps the [paypal api](https://developer.paypal.com/docs/api) asynchronously in a stringly typed manner.
Crate: https://crates.io/crates/paypal-rs
@ -11,6 +11,8 @@ Documentation: https://docs.rs/paypal-rs
Currently in early development.
Note: This README shows how to use the prerelease version, to view the README for `0.1.0` go [here](https://github.com/edg-l/paypal-rs/tree/0.1.0).
## Example
```rust
@ -18,7 +20,8 @@ use paypal_rs::{
Client,
HeaderParams,
Prefer,
orders::{OrderPayload, Intent, PurchaseUnit, Amount}
orders::{OrderPayload, Intent, PurchaseUnit, Amount},
common::Currency,
};
#[tokio::main]
@ -33,7 +36,7 @@ async fn main() {
let order_payload = OrderPayload::new(
Intent::Authorize,
vec![PurchaseUnit::new(Amount::new(
"EUR", "10.0",
Currency::EUR, "10.0",
))],
);

View file

@ -1,6 +1,8 @@
//! Common paypal object definitions used amon 2 or more APIs
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use crate::errors::InvalidCurrencyError;
/// The phone type.
///
@ -71,7 +73,7 @@ pub struct Address {
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct Money {
/// 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: Currency,
/// The value, which might be:
/// - An integer for currencies like JPY that are not typically fractional.
/// - A decimal fraction for currencies like TND that are subdivided into thousandths.
@ -105,3 +107,106 @@ pub struct LinkDescription {
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<LinkMethod>,
}
/// ISO-4217 currency codes.
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum Currency {
/// Australian dollar
AUD,
/// Brazilian real, supported for in country paypal accounts only.
BRL,
/// Canadian dollar
CAD,
/// Chinese Renmenbi
CNY,
/// Czech koruna
CZK,
/// Danish krone
DKK,
/// Euro
EUR,
/// Hong Kong dollar
HKD,
/// Hungarian forint, does not support decimals.
HUF,
/// Indian rupee, supported for in country paypal india accounts only.
INR,
/// Israeli new shekel
ILS,
/// Japanese yen, does not support decimals.
JPY,
/// Malaysian ringgit
MYR,
/// Mexican peso
MXN,
/// New Taiwan dollar, does not support decimals.
TWD,
/// New Zealand dollar
NZD,
/// Norwegian krone
NOK,
/// Philippine peso
PHP,
/// Polish złoty
PLN,
/// Pound sterling
GBP,
/// Russian ruble
RUB,
/// Singapore dollar
SGD,
/// Swedish krona
SEK,
/// Swiss franc
CHF,
/// Thai baht
THB,
/// United States dollar
USD
}
impl Default for Currency {
fn default() -> Self {
Self::EUR
}
}
impl std::fmt::Display for Currency {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self, f)
}
}
impl FromStr for Currency {
type Err = InvalidCurrencyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"AUD" => Ok(Self::AUD),
"BRL" => Ok(Self::BRL),
"CAD" => Ok(Self::CAD),
"CNY" => Ok(Self::CNY),
"CZK" => Ok(Self::CZK),
"DKK" => Ok(Self::DKK),
"EUR" => Ok(Self::EUR),
"HKD" => Ok(Self::HKD),
"HUF" => Ok(Self::HUF),
"INR" => Ok(Self::INR),
"ILS" => Ok(Self::ILS),
"JPY" => Ok(Self::JPY),
"MYR" => Ok(Self::MYR),
"MXN" => Ok(Self::MXN),
"NOK" => Ok(Self::NOK),
"PHP" => Ok(Self::PHP),
"PLN" => Ok(Self::PLN),
"GBP" => Ok(Self::GBP),
"RUB" => Ok(Self::RUB),
"SGD" => Ok(Self::SGD),
"SEK" => Ok(Self::SGD),
"CHF" => Ok(Self::CHF),
"THB" => Ok(Self::THB),
"USD" => Ok(Self::USD),
cur => Err(InvalidCurrencyError(cur.to_owned()))
}
}
}

View file

@ -31,3 +31,15 @@ impl fmt::Display for ApiResponseError {
}
impl Error for ApiResponseError {}
/// When a currency is invalid.
#[derive(Debug)]
pub struct InvalidCurrencyError(pub String);
impl fmt::Display for InvalidCurrencyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} is not a valid currency", self.0)
}
}
impl Error for InvalidCurrencyError {}

View file

@ -308,6 +308,8 @@ impl Client {
#[cfg(test)]
mod tests {
use crate::{orders::*, Client, HeaderParams, Prefer};
use crate::common::Currency;
use std::str::FromStr;
use std::env;
async fn create_client() -> Client {
@ -324,7 +326,7 @@ mod tests {
async fn test_order() {
let mut client = create_client().await;
let order = OrderPayload::new(Intent::Authorize, vec![PurchaseUnit::new(Amount::new("EUR", "10.0"))]);
let order = OrderPayload::new(Intent::Authorize, vec![PurchaseUnit::new(Amount::new(Currency::EUR, "10.0"))]);
let ref_id = format!(
"TEST-{:?}",
@ -359,4 +361,11 @@ mod tests {
.await
.unwrap();
}
#[test]
fn test_currency() {
assert_eq!(Currency::EUR.to_string(), "EUR");
assert_eq!(Currency::JPY.to_string(), "JPY");
assert_eq!(Currency::JPY, Currency::from_str("JPY").unwrap());
}
}

View file

@ -141,7 +141,7 @@ pub struct Breakdown {
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Amount {
/// 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: Currency,
/// The value, which might be:
/// - An integer for currencies like JPY that are not typically fractional.
/// - A decimal fraction for currencies like TND that are subdivided into thousandths.
@ -155,10 +155,10 @@ pub struct Amount {
impl Amount {
/// Creates a new amount with the required values.
pub fn new<S: Into<String>>(currency_code: S, value: S) -> Self {
pub fn new(currency: Currency, value: &str) -> Self {
Amount {
currency_code: currency_code.into(),
value: value.into(),
currency_code: currency,
value: value.to_owned(),
breakdown: None,
}
}