1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//! Application callbacks for billing state changes.
use std::future::Future;
use std::pin::Pin;
use crate::model::{DunningAttempt, Invoice, Subscription};
/// Boxed future returned by hooks.
pub type HookFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
/// Callbacks the application can install with `BillingPlugin::hooks`.
///
/// Every method has a no-op default.
pub trait BillingHooks: Send + Sync + 'static {
/// Map an application user id to a notification recipient id.
///
/// Under Autumn's tenancy feature, `user_id` is an opaque, tenant-scoped
/// identity (`gate::scope_identity_to_tenant`), not the bare session id —
/// two different tenants' sessions can otherwise stringify to the
/// identical id (a sharded deployment's shard-local `BIGSERIAL`,
/// `docs/guide/sharding.md`), and this is the same identity every billing
/// lookup is keyed on. The default recovers the raw id via
/// [`crate::gate::strip_tenant_scope`]; an app overriding this hook and
/// expecting the bare id under tenancy should call that same function
/// rather than parsing the identity's wire format itself (not public
/// API, and not guaranteed stable across releases).
fn recipient_for(&self, user_id: &str) -> Option<i64> {
crate::gate::strip_tenant_scope(user_id).parse().ok()
}
/// A subscription row was created or changed.
fn on_subscription_changed<'a>(
&'a self,
_subscription: &'a Subscription,
_previous: Option<&'a Subscription>,
) -> HookFuture<'a> {
Box::pin(async {})
}
/// A payment failed and a dunning schedule is open.
fn on_payment_failed<'a>(
&'a self,
_invoice: &'a Invoice,
_dunning: &'a DunningAttempt,
) -> HookFuture<'a> {
Box::pin(async {})
}
/// A failed invoice was paid.
fn on_payment_recovered<'a>(&'a self, _invoice: &'a Invoice) -> HookFuture<'a> {
Box::pin(async {})
}
/// Every retry failed.
fn on_dunning_exhausted<'a>(
&'a self,
_invoice: &'a Invoice,
_dunning: &'a DunningAttempt,
) -> HookFuture<'a> {
Box::pin(async {})
}
}
/// Hooks that do nothing.
#[derive(Debug, Default, Clone, Copy)]
pub struct NoHooks;
impl BillingHooks for NoHooks {}