use time::OffsetDateTime;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum Provider {
Stripe,
RevenueCat,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum Store {
AppStore,
MacAppStore,
PlayStore,
Amazon,
Stripe,
RcBilling,
Paddle,
Roku,
Promotional,
TestStore,
Other(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Environment {
Production,
Sandbox,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Ownership {
Purchased,
FamilyShared,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PeriodType {
Trial,
Intro,
Normal,
Promotional,
Prepaid,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProviderCustomer {
pub id: String,
pub original_id: Option<String>,
pub aliases: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SourceRef {
Subscription(String),
OneTimePurchase(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Period {
pub starts_at: OffsetDateTime,
pub ends_at: OffsetDateTime,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum CancelReason {
Unsubscribe,
BillingError,
DeveloperInitiated,
PriceIncrease,
CustomerSupport,
PaymentDisputed,
Unknown,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ExpirationReason {
Unsubscribe,
BillingError,
DeveloperInitiated,
PriceIncrease,
CustomerSupport,
PaymentDisputed,
Unknown,
SubscriptionPaused,
Other(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ChangeTiming {
Immediate,
NextRenewal,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum RefundOrigin {
Store,
Merchant,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum DisputeOutcome {
Won,
Lost,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum LifecycleKind {
Started,
Renewed {
trial_conversion: bool,
},
CancellationScheduled {
reason: CancelReason,
},
Uncancelled,
BillingIssue {
grace_until: Option<OffsetDateTime>,
},
Recovered,
PauseScheduled {
resumes_at: Option<OffsetDateTime>,
},
Paused,
Resumed,
Expired {
reason: ExpirationReason,
},
Extended {
new_ends_at: OffsetDateTime,
},
ProductChanged {
to_product: String,
effective: ChangeTiming,
},
Refunded {
partial: bool,
origin: RefundOrigin,
},
RefundReversed,
DisputeOpened,
DisputeUpdated,
DisputeClosed {
outcome: DisputeOutcome,
},
DisputeFundsWithdrawn,
DisputeFundsReinstated,
OneTimePurchase {
consumable: Option<bool>,
},
Transferred {
from: Vec<String>,
to: Vec<String>,
},
TemporaryGrant {
until: OffsetDateTime,
},
PriceChangeConsentRequired,
PriceChangeConsentApproved,
InvoiceIssued,
Test,
Unrecognized,
}
impl LifecycleKind {
#[must_use]
pub fn is_monotonic_safe(&self) -> bool {
match self {
Self::Refunded { .. }
| Self::DisputeOpened
| Self::DisputeUpdated
| Self::DisputeFundsWithdrawn
| Self::Transferred { .. } => true,
Self::DisputeClosed { outcome } => !matches!(outcome, DisputeOutcome::Won),
Self::Started
| Self::Renewed { .. }
| Self::CancellationScheduled { .. }
| Self::Uncancelled
| Self::BillingIssue { .. }
| Self::Recovered
| Self::PauseScheduled { .. }
| Self::Paused
| Self::Resumed
| Self::Expired { .. }
| Self::Extended { .. }
| Self::ProductChanged { .. }
| Self::RefundReversed
| Self::DisputeFundsReinstated
| Self::OneTimePurchase { .. }
| Self::TemporaryGrant { .. }
| Self::PriceChangeConsentRequired
| Self::PriceChangeConsentApproved
| Self::InvoiceIssued
| Self::Test
| Self::Unrecognized => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LifecycleEvent {
pub provider: Provider,
pub store: Store,
pub event_id: String,
pub occurred_at: OffsetDateTime,
pub environment: Environment,
pub provider_customer: ProviderCustomer,
pub source: SourceRef,
pub product_id: String,
pub entitlement_keys: Vec<String>,
pub period: Option<Period>,
pub period_type: PeriodType,
pub ownership: Ownership,
pub kind: LifecycleKind,
pub raw_kind: String,
}