use chrono::prelude::*;
use reqwest::Method;
use serde::Serialize;
use serde_with::skip_serializing_none;
use crate::entities::{
BillingDetails, Subscription, SubscriptionDiscountEffectiveFrom, SubscriptionPreview,
SubscriptionWithInclude,
};
use crate::enums::{
CollectionMode, CurrencyCode, EffectiveFrom, ProrationBillingMode, ScheduledChangeAction,
SubscriptionInclude, SubscriptionOnPaymentFailure, SubscriptionOnResume, SubscriptionStatus,
};
use crate::ids::{AddressID, BusinessID, CustomerID, PriceID, SubscriptionID};
use crate::paginated::Paginated;
use crate::transactions::TransactionItem;
use crate::{Paddle, Result};
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionsList<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(serialize_with = "crate::comma_separated")]
address_id: Option<Vec<AddressID>>,
after: Option<SubscriptionID>,
collection_mode: Option<CollectionMode>,
#[serde(serialize_with = "crate::comma_separated")]
customer_id: Option<Vec<CustomerID>>,
#[serde(serialize_with = "crate::comma_separated")]
id: Option<Vec<SubscriptionID>>,
order_by: Option<String>,
per_page: Option<usize>,
#[serde(serialize_with = "crate::comma_separated")]
price_id: Option<Vec<PriceID>>,
#[serde(serialize_with = "crate::comma_separated_enum")]
scheduled_change_action: Option<Vec<ScheduledChangeAction>>,
#[serde(serialize_with = "crate::comma_separated_enum")]
status: Option<Vec<SubscriptionStatus>>,
}
impl<'a> SubscriptionsList<'a> {
pub fn new(client: &'a Paddle) -> Self {
Self {
client,
address_id: None,
after: None,
collection_mode: None,
customer_id: None,
id: None,
order_by: None,
per_page: None,
price_id: None,
scheduled_change_action: None,
status: None,
}
}
pub fn address_ids(
&mut self,
address_ids: impl IntoIterator<Item = impl Into<AddressID>>,
) -> &mut Self {
self.address_id = Some(address_ids.into_iter().map(Into::into).collect());
self
}
pub fn after(&mut self, id: impl Into<SubscriptionID>) -> &mut Self {
self.after = Some(id.into());
self
}
pub fn collection_mode(&mut self, mode: CollectionMode) -> &mut Self {
self.collection_mode = Some(mode);
self
}
pub fn customer_id(
&mut self,
customer_ids: impl IntoIterator<Item = impl Into<CustomerID>>,
) -> &mut Self {
self.customer_id = Some(customer_ids.into_iter().map(Into::into).collect());
self
}
pub fn id(&mut self, ids: impl IntoIterator<Item = impl Into<SubscriptionID>>) -> &mut Self {
self.id = Some(ids.into_iter().map(Into::into).collect());
self
}
pub fn order_by_asc(&mut self, field: &str) -> &mut Self {
self.order_by = Some(format!("{}[ASC]", field));
self
}
pub fn order_by_desc(&mut self, field: &str) -> &mut Self {
self.order_by = Some(format!("{}[DESC]", field));
self
}
pub fn per_page(&mut self, entities_per_page: usize) -> &mut Self {
self.per_page = Some(entities_per_page);
self
}
pub fn price_ids(
&mut self,
price_ids: impl IntoIterator<Item = impl Into<PriceID>>,
) -> &mut Self {
self.price_id = Some(price_ids.into_iter().map(Into::into).collect());
self
}
pub fn scheduled_change_action(
&mut self,
actions: impl IntoIterator<Item = ScheduledChangeAction>,
) -> &mut Self {
self.scheduled_change_action = Some(actions.into_iter().collect());
self
}
pub fn status(&mut self, statuses: impl IntoIterator<Item = SubscriptionStatus>) -> &mut Self {
self.status = Some(statuses.into_iter().collect());
self
}
pub fn send(&self) -> Paginated<'_, Vec<Subscription>> {
Paginated::new(self.client, "/subscriptions", self)
}
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionGet<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(skip)]
subscription_id: SubscriptionID,
#[serde(serialize_with = "crate::comma_separated_enum")]
include: Option<Vec<SubscriptionInclude>>,
}
impl<'a> SubscriptionGet<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
include: None,
}
}
pub fn include(
&mut self,
entities: impl IntoIterator<Item = SubscriptionInclude>,
) -> &mut Self {
self.include = Some(entities.into_iter().collect());
self
}
pub async fn send(&self) -> Result<SubscriptionWithInclude> {
self.client
.send(
self,
Method::GET,
&format!("/subscriptions/{}", self.subscription_id.as_ref()),
)
.await
}
}
pub struct SubscriptionPreviewUpdate<'a> {
client: &'a Paddle,
subscription_id: SubscriptionID,
data: serde_json::Value,
}
impl<'a> SubscriptionPreviewUpdate<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
data: serde_json::json!({}),
}
}
pub fn customer_id(&mut self, customer_id: impl Into<CustomerID>) -> &mut Self {
self.data["customer_id"] = serde_json::json!(customer_id.into());
self
}
pub fn address_id(&mut self, address_id: impl Into<AddressID>) -> &mut Self {
self.data["address_id"] = serde_json::json!(address_id.into());
self
}
pub fn business_id(&mut self, business_id: impl Into<BusinessID>) -> &mut Self {
self.data["business_id"] = serde_json::json!(business_id.into());
self
}
pub fn currency_code(&mut self, currency_code: CurrencyCode) -> &mut Self {
self.data["currency_code"] = serde_json::json!(currency_code);
self
}
pub fn next_billed_at(&mut self, next_billed_at: DateTime<Utc>) -> &mut Self {
self.data["next_billed_at"] = serde_json::json!(next_billed_at);
self
}
pub fn set_discount(
&mut self,
discount: Option<SubscriptionDiscountEffectiveFrom>,
) -> &mut Self {
self.data["discount"] = serde_json::json!(discount);
self
}
pub fn collection_mode(&mut self, mode: CollectionMode) -> &mut Self {
self.data["collection_mode"] = serde_json::json!(mode);
self
}
pub fn billing_details(&mut self, billing_details: Option<BillingDetails>) -> &mut Self {
self.data["billing_details"] = serde_json::json!(billing_details);
self
}
pub fn unset_scheduled_change(&mut self) -> &mut Self {
self.data["scheduled_change"] = serde_json::json!(null);
self
}
pub fn items(&mut self, items: impl IntoIterator<Item = TransactionItem>) -> &mut Self {
self.data["items"] = serde_json::json!(items.into_iter().collect::<Vec<_>>());
self
}
pub fn custom_data(&mut self, custom_data: serde_json::Value) -> &mut Self {
self.data["custom_data"] = custom_data;
self
}
pub fn proration_billing_mode(&mut self, mode: ProrationBillingMode) -> &mut Self {
self.data["proration_billing_mode"] = serde_json::json!(mode);
self
}
pub fn on_payment_failure(&mut self, mode: SubscriptionOnPaymentFailure) -> &mut Self {
self.data["on_payment_failure"] = serde_json::json!(mode);
self
}
pub async fn send(&self) -> Result<SubscriptionPreview> {
self.client
.send(
&self.data,
Method::PATCH,
&format!("/subscriptions/{}/preview", self.subscription_id.as_ref()),
)
.await
}
}
pub struct SubscriptionUpdate<'a> {
client: &'a Paddle,
subscription_id: SubscriptionID,
data: serde_json::Value,
}
impl<'a> SubscriptionUpdate<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
data: serde_json::json!({}),
}
}
pub fn customer_id(&mut self, customer_id: impl Into<CustomerID>) -> &mut Self {
self.data["customer_id"] = serde_json::json!(customer_id.into());
self
}
pub fn address_id(&mut self, address_id: impl Into<AddressID>) -> &mut Self {
self.data["address_id"] = serde_json::json!(address_id.into());
self
}
pub fn business_id(&mut self, business_id: impl Into<BusinessID>) -> &mut Self {
self.data["business_id"] = serde_json::json!(business_id.into());
self
}
pub fn currency_code(&mut self, currency_code: CurrencyCode) -> &mut Self {
self.data["currency_code"] = serde_json::json!(currency_code);
self
}
pub fn next_billed_at(&mut self, next_billed_at: DateTime<Utc>) -> &mut Self {
self.data["next_billed_at"] = serde_json::json!(next_billed_at);
self
}
pub fn set_discount(
&mut self,
discount: Option<SubscriptionDiscountEffectiveFrom>,
) -> &mut Self {
self.data["discount"] = serde_json::json!(discount);
self
}
pub fn collection_mode(&mut self, mode: CollectionMode) -> &mut Self {
self.data["collection_mode"] = serde_json::json!(mode);
self
}
pub fn billing_details(&mut self, billing_details: Option<BillingDetails>) -> &mut Self {
self.data["billing_details"] = serde_json::json!(billing_details);
self
}
pub fn unset_scheduled_change(&mut self) -> &mut Self {
self.data["scheduled_change"] = serde_json::json!(null);
self
}
pub fn items(&mut self, items: impl IntoIterator<Item = TransactionItem>) -> &mut Self {
self.data["items"] = serde_json::json!(items.into_iter().collect::<Vec<_>>());
self
}
pub fn custom_data(&mut self, custom_data: serde_json::Value) -> &mut Self {
self.data["custom_data"] = custom_data;
self
}
pub fn proration_billing_mode(&mut self, mode: ProrationBillingMode) -> &mut Self {
self.data["proration_billing_mode"] = serde_json::json!(mode);
self
}
pub fn on_payment_failure(&mut self, mode: SubscriptionOnPaymentFailure) -> &mut Self {
self.data["on_payment_failure"] = serde_json::json!(mode);
self
}
pub async fn send(&self) -> Result<Subscription> {
self.client
.send(
&self.data,
Method::PATCH,
&format!("/subscriptions/{}", self.subscription_id.as_ref()),
)
.await
}
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionOneTimeChargePreview<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(skip)]
subscription_id: SubscriptionID,
effective_from: Option<EffectiveFrom>,
items: Vec<TransactionItem>,
on_payment_failure: Option<SubscriptionOnPaymentFailure>,
}
impl<'a> SubscriptionOneTimeChargePreview<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
effective_from: None,
items: Vec::default(),
on_payment_failure: None,
}
}
pub fn effective_from(&mut self, effective_from: EffectiveFrom) -> &mut Self {
self.effective_from = Some(effective_from);
self
}
pub fn items(&mut self, items: impl IntoIterator<Item = TransactionItem>) -> &mut Self {
self.items = items.into_iter().collect();
self
}
pub fn on_payment_failure(&mut self, mode: SubscriptionOnPaymentFailure) -> &mut Self {
self.on_payment_failure = Some(mode);
self
}
pub async fn send(&self) -> Result<SubscriptionPreview> {
self.client
.send(
self,
Method::POST,
&format!(
"/subscriptions/{}/charge/preview",
self.subscription_id.as_ref()
),
)
.await
}
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionOneTimeCharge<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(skip)]
subscription_id: SubscriptionID,
effective_from: Option<EffectiveFrom>,
items: Vec<TransactionItem>,
on_payment_failure: Option<SubscriptionOnPaymentFailure>,
}
impl<'a> SubscriptionOneTimeCharge<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
effective_from: None,
items: Vec::default(),
on_payment_failure: None,
}
}
pub fn effective_from(&mut self, effective_from: EffectiveFrom) -> &mut Self {
self.effective_from = Some(effective_from);
self
}
pub fn items(&mut self, items: impl IntoIterator<Item = TransactionItem>) -> &mut Self {
self.items = items.into_iter().collect();
self
}
pub fn on_payment_failure(&mut self, mode: SubscriptionOnPaymentFailure) -> &mut Self {
self.on_payment_failure = Some(mode);
self
}
pub async fn send(&self) -> Result<Subscription> {
self.client
.send(
self,
Method::POST,
&format!("/subscriptions/{}/charge", self.subscription_id.as_ref()),
)
.await
}
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionPause<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(skip)]
subscription_id: SubscriptionID,
effective_from: Option<EffectiveFrom>,
resume_at: Option<DateTime<Utc>>,
on_resume: Option<SubscriptionOnResume>,
}
impl<'a> SubscriptionPause<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
effective_from: None,
resume_at: None,
on_resume: None,
}
}
pub fn effective_from(&mut self, effective_from: EffectiveFrom) -> &mut Self {
self.effective_from = Some(effective_from);
self
}
pub fn resume_at(&mut self, datetime: DateTime<Utc>) -> &mut Self {
self.resume_at = Some(datetime);
self
}
pub fn on_resume(&mut self, value: SubscriptionOnResume) -> &mut Self {
self.on_resume = Some(value);
self
}
pub async fn send(&self) -> Result<Subscription> {
self.client
.send(
self,
Method::POST,
&format!("/subscriptions/{}/pause", self.subscription_id.as_ref()),
)
.await
}
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionResume<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(skip)]
subscription_id: SubscriptionID,
effective_from: Option<DateTime<Utc>>,
on_resume: Option<SubscriptionOnResume>,
}
impl<'a> SubscriptionResume<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
effective_from: None,
on_resume: None,
}
}
pub fn effective_from(&mut self, effective_from: DateTime<Utc>) -> &mut Self {
self.effective_from = Some(effective_from);
self
}
pub fn on_resume(&mut self, value: SubscriptionOnResume) -> &mut Self {
self.on_resume = Some(value);
self
}
pub async fn send(&self) -> Result<Subscription> {
self.client
.send(
self,
Method::POST,
&format!("/subscriptions/{}/resume", self.subscription_id.as_ref()),
)
.await
}
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct SubscriptionCancel<'a> {
#[serde(skip)]
client: &'a Paddle,
#[serde(skip)]
subscription_id: SubscriptionID,
effective_from: Option<EffectiveFrom>,
}
impl<'a> SubscriptionCancel<'a> {
pub fn new(client: &'a Paddle, subscription_id: impl Into<SubscriptionID>) -> Self {
Self {
client,
subscription_id: subscription_id.into(),
effective_from: None,
}
}
pub fn effective_from(&mut self, effective_from: EffectiveFrom) -> &mut Self {
self.effective_from = Some(effective_from);
self
}
pub async fn send(&self) -> Result<Subscription> {
self.client
.send(
self,
Method::POST,
&format!("/subscriptions/{}/cancel", self.subscription_id.as_ref()),
)
.await
}
}