Skip to content

Commit

Permalink
feat: create subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
jackskelt committed Oct 21, 2023
1 parent 177a0f6 commit 0d9b226
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Just to run tests locally
MERCADO_PAGO_ACCESS=
MERCADO_PAGO_ACCESS=
MP_EMAIL=
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod common;
pub mod oauth;
pub mod payer;
pub mod payments;
pub mod subscription;

/// The base URL for Mercado Pago API
pub static API_BASE_URL: &str = "https://api.mercadopago.com";
3 changes: 3 additions & 0 deletions src/subscription.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod types;

pub mod create_builder;
89 changes: 89 additions & 0 deletions src/subscription/create_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::client::MercadoPagoClient;
use crate::common::{resolve_json, MercadoPagoRequestError};
use crate::subscription::types::{
AutoRecurring, Subscription, SubscriptionCreateOptions, SubscriptionStatus,
};
use reqwest::Method;

pub struct SubscriptionCreateBuilder(pub SubscriptionCreateOptions);

impl SubscriptionCreateBuilder {
pub async fn send(
self,
mp_client: &MercadoPagoClient,
) -> Result<Subscription, MercadoPagoRequestError> {
let res = mp_client
.start_request(Method::POST, "/preapproval")
.json(&self.0)
.send()
.await?;

dbg!("{}", res.status());

resolve_json::<Subscription>(res).await
}

pub fn create_without_plan(
recurring_info: AutoRecurring,
payer_email: String,
reason: String,
back_url: String,
) -> SubscriptionCreateBuilder {
SubscriptionCreateBuilder(SubscriptionCreateOptions {
auto_recurring: Some(recurring_info),
back_url,
payer_email,
reason: Some(reason),
status: SubscriptionStatus::Pending,
..Default::default()
})
}

pub fn create_with_plan(
preapproval_plan_id: String,
payer_email: String,
card_token_id: String,
back_url: String,
) -> SubscriptionCreateBuilder {
SubscriptionCreateBuilder(SubscriptionCreateOptions {
back_url,
payer_email,
card_token_id: Some(card_token_id),
preapproval_plan_id: Some(preapproval_plan_id),
status: SubscriptionStatus::Authorized,
..Default::default()
})
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::common::{create_test_client, CurrencyId};
use crate::subscription::types::*;
use rust_decimal::Decimal;

#[tokio::test]
#[ignore]
async fn create_without_plan() {
let mp_client = create_test_client();

let subscription = SubscriptionCreateBuilder::create_without_plan(
AutoRecurring {
frequency: 1,
frequency_type: FrequencyType::Months,
transaction_amount: Decimal::new(10, 0),
currency_id: CurrencyId::BRL,
..Default::default()
},
std::env::var("MP_EMAIL").unwrap(),
String::from("Testing"),
String::from("https://google.com"),
)
.send(&mp_client)
.await
.unwrap();

println!("{subscription:?}");
}
}
127 changes: 127 additions & 0 deletions src/subscription/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use crate::common::CurrencyId;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct SubscriptionCreateOptions {
pub auto_recurring: Option<AutoRecurring>,
pub back_url: String,
pub card_token_id: Option<String>,
pub external_reference: Option<String>,
pub payer_email: String,
pub preapproval_plan_id: Option<String>,
pub reason: Option<String>,
pub status: SubscriptionStatus,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct SubscriptionSearchParams {
q: Option<String>,
payer_id: Option<u16>,
payer_email: Option<String>,
preapproval_plan_id: Option<String>,
#[serde(with = "rust_decimal::serde::float_option")]
transaction_amount: Option<Decimal>,
semaphore: Option<SubscriptionSemaphore>,
sort: Option<String>,
offset: Option<u32>,
limit: Option<u32>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Subscription {
pub id: String,
pub application_id: u128,
pub collector_id: u32,
pub preapproval_plan_id: Option<String>,
pub reason: String,
pub external_reference: Option<String>,
pub back_url: String,
pub init_point: String,
pub auto_recurring: AutoRecurring,
pub payer_id: u32,
pub card_id: Option<u16>,
pub payment_method_id: Option<u16>,
pub next_payment_date: Option<String>,
pub date_created: Option<String>,
pub last_modified: Option<String>,
pub status: SubscriptionStatus,
pub summarized: Option<SubscriptionSummarized>,
pub first_invoice_offset: Option<u8>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct UpdateSubscriptionRequest {
pub auto_recurring: Option<AutoRecurring>,
pub back_url: Option<String>,
pub card_token_id: Option<u32>,
pub external_reference: Option<String>,
pub reason: Option<String>,
pub status: Option<SubscriptionStatus>,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct UpdateAutoRecurring {
#[serde(with = "rust_decimal::serde::float_option")]
pub transaction_amount: Option<Decimal>,
pub currency_id: Option<CurrencyId>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct SubscriptionSummarized {
pub quotas: Option<u32>,
pub charge_quantity: Option<u32>,
pub pending_charge_quantity: Option<u32>,
#[serde(with = "rust_decimal::serde::float_option")]
pub charged_amount: Option<Decimal>,
#[serde(with = "rust_decimal::serde::float_option")]
pub pending_charge_amount: Option<Decimal>,
pub semaphore: Option<SubscriptionSemaphore>,
pub last_charged_date: Option<String>,
#[serde(with = "rust_decimal::serde::float_option")]
pub last_charged_amount: Option<Decimal>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SubscriptionSemaphore {
Green,
Yellow,
Ged,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SubscriptionStatus {
#[default]
Pending,
Authorized,
Paused,
Cancelled,
}

#[derive(Serialize, Deserialize, Default, Debug)]
pub struct AutoRecurring {
pub frequency: u8,
pub frequency_type: FrequencyType,
pub start_date: Option<String>,
pub end_date: Option<String>,
pub currency_id: CurrencyId,
#[serde(with = "rust_decimal::serde::float")]
pub transaction_amount: Decimal,
pub free_trial: Option<FreeTrial>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct FreeTrial {
pub frequency: u8,
pub frequency_type: FrequencyType,
}

#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(rename_all = "snake_case")]
pub enum FrequencyType {
#[default]
Days,
Months,
}

0 comments on commit 0d9b226

Please sign in to comment.