rustlavel_billing/lib.rs
1//! rustlavel-billing: subscriptions where the customer pays, rather than is
2//! charged.
3//!
4//! In a market where cards are rare and virtual accounts, QRIS and e-wallets
5//! are how people pay, a subscription cannot pull money. It can only *ask*:
6//! each cycle it raises an invoice, presents a way to pay it, and waits. This
7//! crate is that loop.
8//!
9//! # The cycle
10//!
11//! 1. [`Billing::subscribe`] creates the subscription, its first invoice, and
12//! a charge at the payment gateway — the VA number or QR the customer pays.
13//! 2. The gateway's webhook says paid. The application's receiver calls
14//! [`Billing::on_paid`], which marks the invoice paid, extends the
15//! subscription by one cycle, and credits the plan's allowance through the
16//! ledger — idempotently, under the invoice's id, so a retried webhook
17//! credits once.
18//! 3. [`Billing::tick`] runs on a schedule. When a period ends it raises the
19//! next invoice and charge; while an invoice is unpaid past the period's
20//! end the subscription is in grace; when grace runs out it is suspended.
21//! `tick` returns the [`Reminder`]s that fell due, and the application
22//! sends them — this crate does not know what the mail should say.
23//!
24//! # What this does not do
25//!
26//! Overage. A customer who wants more credits than the plan gives buys a
27//! top-up, which is one charge and one `Ledger::top_up` and needs no machinery
28//! here. Proration on plan change is a policy decision this crate does not
29//! make for you: [`Billing::change_plan`] takes effect at the next cycle.
30
31pub mod billing;
32pub mod plan;
33pub mod schema;
34pub mod subscription;
35
36pub use billing::{Billing, Paid, Reminder, ReminderKind, Tick};
37pub use plan::{Cycle, Plan};
38pub use schema::{CreateBillingTables, create_tables, drop_tables};
39pub use subscription::{Invoice, InvoiceStatus, Subscriber, Subscription, SubscriptionStatus};
40pub use rustlavel_payment::{Channel, Instructions, Money};
41
42pub use rustlavel_core::{Error, Result};