use super::seats::SeatChecker;
use crate::billing::seats::SeatManager;
use crate::billing::storage::BillingStore;
use crate::billing::subscription::StripeSubscriptionClient;
use crate::error::Result;
use async_trait::async_trait;
pub trait BillableOrganization {
fn billable_id(&self) -> &str;
fn contact_email(&self) -> &str;
fn name(&self) -> &str;
}
impl<T: BillableOrganization + Send + Sync> crate::billing::BillableEntity for T {
fn billable_id(&self) -> &str {
BillableOrganization::billable_id(self)
}
fn billable_type(&self) -> &str {
"org"
}
fn email(&self) -> &str {
BillableOrganization::contact_email(self)
}
fn name(&self) -> Option<&str> {
Some(BillableOrganization::name(self))
}
}
pub struct BillingSeatChecker<B: BillingStore, C: StripeSubscriptionClient> {
seat_manager: SeatManager<B, C>,
}
impl<B, C> BillingSeatChecker<B, C>
where
B: BillingStore,
C: StripeSubscriptionClient,
{
pub fn new(seat_manager: SeatManager<B, C>) -> Self {
Self { seat_manager }
}
pub fn seat_manager(&self) -> &SeatManager<B, C> {
&self.seat_manager
}
}
#[async_trait]
impl<B, C> SeatChecker for BillingSeatChecker<B, C>
where
B: BillingStore + Send + Sync,
C: StripeSubscriptionClient + Send + Sync,
{
async fn has_seat_available(&self, org_id: &str, current_count: u32) -> Result<bool> {
self.seat_manager
.has_seat_available(org_id, current_count)
.await
}
async fn get_seat_limit(&self, org_id: &str) -> Result<Option<u32>> {
let info = self.seat_manager.get_seat_info(org_id).await?;
Ok(Some(info.total_seats))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone)]
struct TestOrg {
id: String,
name: String,
email: String,
}
impl BillableOrganization for TestOrg {
fn billable_id(&self) -> &str {
&self.id
}
fn contact_email(&self) -> &str {
&self.email
}
fn name(&self) -> &str {
&self.name
}
}
#[test]
fn test_billable_organization_trait() {
let org = TestOrg {
id: "org_123".to_string(),
name: "Test Org".to_string(),
email: "test@example.com".to_string(),
};
assert_eq!(BillableOrganization::billable_id(&org), "org_123");
assert_eq!(
BillableOrganization::contact_email(&org),
"test@example.com"
);
assert_eq!(BillableOrganization::name(&org), "Test Org");
}
#[test]
fn test_billable_entity_blanket_impl() {
use crate::billing::BillableEntity;
let org = TestOrg {
id: "org_456".to_string(),
name: "Another Org".to_string(),
email: "another@example.com".to_string(),
};
assert_eq!(BillableEntity::billable_id(&org), "org_456");
assert_eq!(BillableEntity::billable_type(&org), "org");
assert_eq!(BillableEntity::email(&org), "another@example.com");
assert_eq!(BillableEntity::name(&org), Some("Another Org"));
}
}