73 lines
3.5 KiB
HTML
73 lines
3.5 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ _('Admin · Transactions') }}{% endblock %}
|
|
{% block content %}
|
|
{% include "admin/_nav.html" %}
|
|
<div class="card">
|
|
<h2>{{ _('Transactions') }}</h2>
|
|
<p class="muted">{{ _('All-time revenue (succeeded): $%(amount)s', amount='%.2f'|format(total_cents / 100)) }}</p>
|
|
|
|
<form method="get" class="admin-filter-row">
|
|
<div class="field">
|
|
<label>{{ _('Type') }}</label>
|
|
<select class="input" name="type">
|
|
<option value="">{{ _('All') }}</option>
|
|
<option value="subscription" {{ 'selected' if filters.get('type') == 'subscription' }}>{{ _('Subscription') }}</option>
|
|
<option value="boost" {{ 'selected' if filters.get('type') == 'boost' }}>{{ _('Boost') }}</option>
|
|
<option value="refund" {{ 'selected' if filters.get('type') == 'refund' }}>{{ _('Refund') }}</option>
|
|
</select>
|
|
</div>
|
|
<div class="field">
|
|
<label>{{ _('Status') }}</label>
|
|
<select class="input" name="status">
|
|
<option value="">{{ _('All') }}</option>
|
|
<option value="succeeded" {{ 'selected' if filters.get('status') == 'succeeded' }}>{{ _('Succeeded') }}</option>
|
|
<option value="failed" {{ 'selected' if filters.get('status') == 'failed' }}>{{ _('Failed') }}</option>
|
|
<option value="pending" {{ 'selected' if filters.get('status') == 'pending' }}>{{ _('Pending') }}</option>
|
|
</select>
|
|
</div>
|
|
<button class="btn ghost" type="submit">{{ _('Filter') }}</button>
|
|
{% if filters.get('type') or filters.get('status') %}<a class="btn ghost" href="{{ url_for('admin.transactions') }}">{{ _('Clear') }}</a>{% endif %}
|
|
</form>
|
|
|
|
<table class="list">
|
|
<thead><tr>
|
|
<th>{{ _('Date') }}</th>
|
|
<th>{{ _('User') }}</th>
|
|
<th>{{ _('Type') }}</th>
|
|
<th>{{ _('Amount') }}</th>
|
|
<th>{{ _('Status') }}</th>
|
|
<th>{{ _('Stripe ID') }}</th>
|
|
<th></th>
|
|
</tr></thead>
|
|
{% for txn in pagination.items %}
|
|
<tr>
|
|
<td class="muted small">{{ txn.created_at.strftime('%Y-%m-%d') }}</td>
|
|
<td><a href="{{ url_for('admin.user_detail', user_id=txn.user_id) }}">{{ txn.user.display_name }}</a></td>
|
|
<td><span class="badge cat">{{ txn.type }}</span></td>
|
|
<td>${{ '%.2f'|format(txn.amount_cents / 100) }}</td>
|
|
<td><span class="badge {{ 'ok' if txn.status == 'succeeded' else 'warn' }}">{{ txn.status }}</span></td>
|
|
<td class="muted small">{{ txn.stripe_object_id or '—' }}</td>
|
|
<td>
|
|
{% if txn.status == 'succeeded' and txn.type != 'refund' %}
|
|
<form method="post"
|
|
action="{{ url_for('admin.refund_transaction', txn_id=txn.id) }}"
|
|
onsubmit="return confirm('{{ _('Issue refund for $%(a)s?', a='%.2f'|format(txn.amount_cents/100)) }}');">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<button class="btn ghost tiny" type="submit">{{ _('Refund') }}</button>
|
|
</form>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="6" class="muted">{{ _('No transactions.') }}</td></tr>
|
|
{% endfor %}
|
|
</table>
|
|
|
|
<div class="pager">
|
|
{% if pagination.has_prev %}<a href="{{ url_for('admin.transactions', **merge_query(page=pagination.prev_num)) }}">← {{ _('Prev') }}</a>{% endif %}
|
|
<span class="muted">{{ _('Page %(p)s of %(t)s', p=pagination.page, t=pagination.pages) }}</span>
|
|
{% if pagination.has_next %}<a href="{{ url_for('admin.transactions', **merge_query(page=pagination.next_num)) }}">{{ _('Next') }} →</a>{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|