Skip to content

Commit

Permalink
Merge pull request #1 from montdidier/feature/refunds
Browse files Browse the repository at this point in the history
add refunds
  • Loading branch information
montdidier authored Dec 19, 2023
2 parents 8c6e532 + 9d2f7ac commit c9ce38f
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/resources.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod currency;
mod charge;
mod card;
mod refund;

pub use currency::*;
pub use charge::*;
pub use card::*;
pub use refund::*;
77 changes: 77 additions & 0 deletions src/resources/refund.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use time::{OffsetDateTime};
use serde::{Deserialize, Serialize};

use crate::client::{Client, Response};
use crate::error::PinError;
use crate::ids::{RefundId, ChargeId};
use crate::params::{Page, Paginator, unpack_contained, paginate};
use crate::resources::{
Currency
};
use crate::build_map;

#[derive(Clone, Debug, Serialize, Default)]
pub struct CreateRefund {
pub amount: Option<i64>
}

#[derive(Clone, Debug, Default, Deserialize)]
pub struct Refund {
pub token: RefundId,
pub success: Option<bool>,
pub amount: i64,
pub currency: Currency,
pub charge: ChargeId,
#[serde(with = "time::serde::iso8601::option")]
pub created_at: Option<OffsetDateTime>,
pub error_message: Option<String>,
pub status_message: String
}

impl Refund {
pub fn create(client: &Client, token: &ChargeId, params: CreateRefund) -> Response<Refund> {
unpack_contained(client.post_form(&format!("/charges/{}/refunds", token), &params))
}

pub fn list(client: &Client, page: Option<u32>, per_page: Option<u32>) -> Response<Page<Refund>> {
let page = page.map(|s| s.to_string());
let per_page = per_page.map(|s| s.to_string());
let params = build_map([
("page", page.as_deref()),
("per_page", per_page.as_deref())
]);
client.get_query("/refunds", &params)
}

pub fn list_with_paginator(client: &Client, per_page: Option<u32>) -> Paginator<Result<Refund, PinError>> {
paginate(
move |page, per_page| {
Refund::list(client, Some(page), Some(per_page))
},
per_page.unwrap_or(25)
)
}

pub fn list_for_charge(client: &Client, token: &ChargeId, page: Option<u32>, per_page: Option<u32>) -> Response<Page<Refund>> {
let page = page.map(|s| s.to_string());
let per_page = per_page.map(|s| s.to_string());
let params = build_map([
("page", page.as_deref()),
("per_page", per_page.as_deref())
]);
client.get_query(&format!("/charges/{}/refunds", token), &params)
}

pub fn list_for_charge_with_paginator<'a>(client: &'a Client, token: &'a ChargeId, per_page: Option<u32>) -> Paginator<'a, Result<Refund, PinError>> {
paginate(
move |page, per_page| {
Refund::list_for_charge(client, token, Some(page), Some(per_page))
},
per_page.unwrap_or(25)
)
}

pub fn retrieve(client: &Client, token: &RefundId) -> Response<Refund> {
unpack_contained(client.get(&format!("/refunds/{}", token)))
}
}
12 changes: 12 additions & 0 deletions tests/fixtures/create-refund.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"response": {
"token": "rf_ERCQy--Ay6o-NKGiUVcKKA",
"success": null,
"amount": 400,
"currency": "USD",
"charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA",
"created_at": "2012-10-27T13:00:00Z",
"error_message": null,
"status_message": "Pending"
}
}
23 changes: 23 additions & 0 deletions tests/fixtures/get-charge-refunds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"response": [
{
"token": "rf_ERCQy--Ay6o-NKGiUVcKKA",
"success": null,
"amount": 400,
"currency": "USD",
"charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA",
"created_at": "2012-10-27T13:00:00Z",
"error_message": null,
"status_message": "Pending"
}
],
"count": 1,
"pagination": {
"current": 1,
"previous": null,
"next": null,
"per_page": 25,
"pages": 1,
"count": 1
}
}
12 changes: 12 additions & 0 deletions tests/fixtures/get-refund.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"response": {
"token": "rf_ERCQy--Ay6o-NKGiUVcKKA",
"success": null,
"amount": 400,
"currency": "USD",
"charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA",
"created_at": "2012-10-27T13:00:00Z",
"error_message": null,
"status_message": "Pending"
}
}
23 changes: 23 additions & 0 deletions tests/fixtures/get-refunds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"response": [
{
"token": "rf_ERCQy--Ay6o-NKGiUVcKKA",
"success": null,
"amount": 400,
"currency": "USD",
"charge": "ch_bZ3RhJnIUZ8HhfvH8CCvfA",
"created_at": "2012-10-27T13:00:00Z",
"error_message": null,
"status_message": "Pending"
}
],
"count": 1,
"pagination": {
"current": 1,
"previous": null,
"next": null,
"per_page": 25,
"pages": 1,
"count": 1
}
}
128 changes: 128 additions & 0 deletions tests/refund.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use pinpayments::{Client, Currency, CreateRefund, Refund};
use std::fs::File;
use httptest::{ServerPool, Expectation, matchers::*, responders::*};
use surf::http::auth::BasicAuth;
use time::macros::datetime;

static SERVER_POOL: ServerPool = ServerPool::new(2);

fn get_fixture(path: &str) -> serde_json::Value {
let file = File::open(path)
.expect("file should open read only");
serde_json::from_reader(file).expect("file should be JSON")
}

#[tokio::test]
async fn charge_refund_test() {
let json = get_fixture("tests/fixtures/create-refund.json");

let auth = BasicAuth::new("sk_test_12345", "");

let server = SERVER_POOL.get_server();

let charge_token = "ch_bZ3RhJnIUZ8HhfvH8CCvfA".parse().unwrap();

server.expect(
Expectation::matching(
all_of![
request::method_path("POST", format!("/1/charges/{}/refunds", charge_token)),
request::headers(
contains((String::from(auth.name().as_str()), String::from(auth.value().as_str())))
),
]).
respond_with(
status_code(201)
.append_header("Content-Type", "application/json")
.body(serde_json::to_string(&json).expect("failed to serialize body"))),
);

let client = Client::from_url(server.url_str("/1/").as_str(), "sk_test_12345");

let refund = Refund::create(
&client,
&charge_token,
CreateRefund {
amount: None
}
)
.await
.unwrap();

assert_eq!(refund.token, "rf_ERCQy--Ay6o-NKGiUVcKKA");
}

#[tokio::test]
async fn refund_list_test() {
let json = get_fixture("tests/fixtures/get-refunds.json");

let server = SERVER_POOL.get_server();

server.expect(
Expectation::matching(request::method_path("GET", "/1/refunds")).
respond_with(json_encoded(json)),
);

let client = Client::from_url(server.url_str("/1/").as_str(), "sk_test_12345");
let refunds = Refund::list(&client, None, None).await.unwrap();

assert_eq!(refunds.items[0].token, "rf_ERCQy--Ay6o-NKGiUVcKKA");
assert_eq!(refunds.items[0].success, None);
assert_eq!(refunds.items[0].amount, 400);
assert_eq!(refunds.items[0].currency, Currency::USD);
assert_eq!(refunds.items[0].charge, "ch_bZ3RhJnIUZ8HhfvH8CCvfA");
assert_eq!(refunds.items[0].created_at.unwrap(), datetime!(2012-10-27 13:00 UTC));
assert_eq!(refunds.items[0].error_message, None);
assert_eq!(refunds.items[0].status_message, "Pending");
}

#[tokio::test]
async fn charge_refunds_test() {
let json = get_fixture("tests/fixtures/get-refunds.json");

let server = SERVER_POOL.get_server();

let charge_token = "ch_bZ3RhJnIUZ8HhfvH8CCvfA".parse().unwrap();

server.expect(
Expectation::matching(request::method_path("GET", format!("/1/charges/{}/refunds", charge_token))).
respond_with(json_encoded(json)),
);

let client = Client::from_url(server.url_str("/1/").as_str(), "sk_test_12345");
let refunds = Refund::list_for_charge(&client, &charge_token, None, None).await.unwrap();

assert_eq!(refunds.items[0].token, "rf_ERCQy--Ay6o-NKGiUVcKKA");
assert_eq!(refunds.items[0].success, None);
assert_eq!(refunds.items[0].amount, 400);
assert_eq!(refunds.items[0].currency, Currency::USD);
assert_eq!(refunds.items[0].charge, "ch_bZ3RhJnIUZ8HhfvH8CCvfA");
assert_eq!(refunds.items[0].created_at.unwrap(), datetime!(2012-10-27 13:00 UTC));
assert_eq!(refunds.items[0].error_message, None);
assert_eq!(refunds.items[0].status_message, "Pending");
}

#[tokio::test]
async fn get_refund_test() {
let json = get_fixture("tests/fixtures/get-refund.json");

let server = SERVER_POOL.get_server();

let refund_token = "rf_ERCQy--Ay6o-NKGiUVcKKA".parse().unwrap();

server.expect(
Expectation::matching(request::method_path("GET", format!("/1/refunds/{}", refund_token))).
respond_with(json_encoded(json)),
);

let client = Client::from_url(server.url_str("/1/").as_str(), "sk_test_12345");
let refund = Refund::retrieve(&client, &refund_token).await.unwrap();

assert_eq!(refund.token, "rf_ERCQy--Ay6o-NKGiUVcKKA");
assert_eq!(refund.success, None);
assert_eq!(refund.amount, 400);
assert_eq!(refund.currency, Currency::USD);
assert_eq!(refund.charge, "ch_bZ3RhJnIUZ8HhfvH8CCvfA");
assert_eq!(refund.created_at.unwrap(), datetime!(2012-10-27 13:00 UTC));
assert_eq!(refund.error_message, None);
assert_eq!(refund.status_message, "Pending");
}

0 comments on commit c9ce38f

Please sign in to comment.