# django-lark

Django integration for [Lark billing](https://uselark.ai).

## Installation

```bash
pip install django-lark
```

## Quick Start

1. Add `django_lark` to your `INSTALLED_APPS`:

```python
INSTALLED_APPS = [
    ...
    'django_lark',
]
```

2. Configure your Lark API key in `settings.py`:

```python
LARK_API_KEY = "lark_api_..."
```

Or set the `LARK_API_KEY` environment variable.

3. Include the URLs (optional, for customer portal):

```python
urlpatterns = [
    ...
    path('billing/', include('django_lark.urls')),
]
```

## Configuration

All settings are prefixed with `LARK_`:

| Setting | Default | Description |
|---------|---------|-------------|
| `LARK_API_KEY` | Required | Your Lark API key |
| `LARK_BASE_URL` | `https://api.uselark.ai` | Lark API base URL |
| `LARK_TIMEOUT` | `60.0` | Request timeout in seconds |
| `LARK_MAX_RETRIES` | `2` | Max retry attempts |
| `LARK_USER_SUBJECT_FIELD` | `email` | User field to use as external_id |
| `LARK_AUTO_CREATE_SUBJECTS` | `False` | Auto-create Lark subjects for users |
| `LARK_BILLING_STATE_CACHE_TIMEOUT` | `300` | Cache timeout for billing state (seconds) |

## How It Works

django-lark uses Lark's `external_id` feature to identify users without maintaining a local database mapping. When you create a subject in Lark with an `external_id`, you can use that same `external_id` in any API call that accepts a `subject_id`.

By default, django-lark uses the user's email as the `external_id`. You can customize this with the `LARK_USER_SUBJECT_FIELD` setting:

```python
# Use user's primary key
LARK_USER_SUBJECT_FIELD = "id"  # Results in "django_user_{pk}"

# Use email (default)
LARK_USER_SUBJECT_FIELD = "email"

# Use a custom field
LARK_USER_SUBJECT_FIELD = "uuid"

# Use a callable for full control
LARK_USER_SUBJECT_FIELD = lambda user: f"myapp_{user.organization_id}_{user.id}"
```

## Usage

### Client Access

```python
from django_lark import get_lark_client, get_async_lark_client

# Sync
client = get_lark_client()
subjects = client.subjects.list()

# Async
async def my_view(request):
    client = get_async_lark_client()
    subjects = await client.subjects.list()
```

### Get External ID for a User

```python
from django_lark.utils import get_external_id_for_user

external_id = get_external_id_for_user(user)
# Use this external_id in any Lark API call
```

### Create Lark Subjects for Users

```python
from django_lark.utils import get_or_create_subject_for_user

# Get or create a Lark subject for a Django user
subject, created = get_or_create_subject_for_user(user)
```

### Check Subscription Status

```python
from django_lark.utils import get_billing_state_for_user

billing_state = get_billing_state_for_user(user)
if billing_state.has_active_subscription:
    print("User has active subscription!")
```

### View Decorators

```python
from django_lark.decorators import subscription_required

@subscription_required()
def premium_view(request):
    return render(request, 'premium.html')

@subscription_required(rate_card_ids=['rc_pro', 'rc_enterprise'])
def pro_view(request):
    return render(request, 'pro.html')

@subscription_required(redirect_url='/pricing/')
def feature_view(request):
    return render(request, 'feature.html')
```

### Template Tags

```django
{% load lark_tags %}

{% has_active_subscription as is_subscribed %}
{% if is_subscribed %}
    <p>Welcome, premium member!</p>
{% else %}
    <a href="/pricing/">Upgrade now</a>
{% endif %}

{% has_subscription_to_rate_card "rc_pro" as has_pro %}
{% if has_pro %}
    <p>Pro features unlocked!</p>
{% endif %}

{% get_subscriptions as subscriptions %}
{% for sub in subscriptions %}
    <p>{{ sub.rate_card_id }} -
       <span class="badge {{ sub.status|lark_subscription_status_badge }}">
           {{ sub.status }}
       </span>
    </p>
{% endfor %}

{% get_lark_external_id as external_id %}
```

### Customer Portal

Redirect users to the Lark customer portal:

```django
<a href="{% url 'django_lark:customer_portal' %}?return_url={{ request.path }}">
    Manage Subscription
</a>
```

## License

MIT
