Skip to content
8 changes: 4 additions & 4 deletions docs/content/en/docs/Architecture/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The test suite needs to listen to these events locally when running tests.

tldr:
1. Install the Stripe cli
2. Run `stripe listen --events checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed,payment_intent.payment_failed --forward-to 127.0.0.1:5000/stripe_webhook`
2. Run `stripe listen --events checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed,payment_intent.payment_failed,payment_intent.requires_action,invoice.payment_failed --forward-to 127.0.0.1:5000/stripe_webhook`

> For testing failed payments using [test cards table](https://stripe.com/docs/testing), the test card `4000000000000341` is especially useful because the cards in the previous table can’t be attached to a Customer object, but `4000000000000341` can be (and will fail which is useful for testing failed subscription payments such as `insufficient_funds`).

Expand All @@ -69,15 +69,15 @@ If you're doing local development, then you need Stripe to send you the test pay
2. Login into stripe via `stripe login` (this shoud open the browser with stripe page where you should enter your credentials). If this command doesn't work use `stripe login -i` (this will login you in interactive mode where instead of opening browser you'll have to put Stripe secret key directly into terminal)
3. Run
```
stripe listen --events checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed --forward-to 127.0.0.1:5000/stripe_webhook
stripe listen --events checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed,payment_intent.payment_failed,payment_intent.requires_action,invoice.payment_failed --forward-to 127.0.0.1:5000/stripe_webhook
```
You will see:
```
⢿ Getting ready... > Ready!
```
4. Please note, the stripe webhook secret is *not* needed for local development - for production, Stripe webhook verification is done in [Stripe-connect-webhook-endpoint-router](https://github.com/Subscribie/stripe-connect-webhook-endpoint-router) (you don't need this for local development).
```
stripe listen --events checkout.session.completed,payment_intent.succeeded --forward-to 127.0.0.1:5000/stripe_webhook
stripe listen --events checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed,payment_intent.payment_failed,payment_intent.requires_action,invoice.payment_failed --forward-to 127.0.0.1:5000/stripe_webhook
```
Remember Stripe will give you a key valid for 90 days, if you get the following error you will need to do step 2 again:

Expand All @@ -94,7 +94,7 @@ Error while authenticating with Stripe: Authorization failed, status=401

## Run Playwright tests
> **Important:** Stripe cli must be running locally to recieve payment events:
>`stripe listen --events checkout.session.completed,payment_intent.succeeded --forward-to 127.0.0.1:5000/stripe_webhook`
>`stripe listen --events checkout.session.completed,payment_intent.succeeded,payment_intent.payment_failed,payment_intent.payment_failed,payment_intent.requires_action,invoice.payment_failed --forward-to 127.0.0.1:5000/stripe_webhook`

<br />

Expand Down
21 changes: 14 additions & 7 deletions subscribie/blueprints/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,20 @@ def refund_stripe_subscription(payment_id):
)
if "confirm" in request.args and request.args["confirm"] == "1":
try:
stripe_refund = stripe.Refund.create(
payment_intent=payment_id,
stripe_account=connect_account_id,
)
if Transaction.query.filter_by(external_id=payment_id).first() is None:
return "payment doesn't exist"
if (
Transaction.query.filter_by(external_id=payment_id).first() is None
or Transaction.query.filter_by(external_id=payment_id)
.first()
.payment_status
!= "paid"
):
flash("The transaction doesn't exist or wasn't succesful")
return redirect(url_for("admin.transactions"))
else:
stripe_refund = stripe.Refund.create(
payment_intent=payment_id,
stripe_account=connect_account_id,
)
transaction = Transaction.query.filter_by(external_id=payment_id).first()
transaction.external_refund_id = stripe_refund.id
database.session.commit()
Expand Down Expand Up @@ -1398,7 +1406,6 @@ def transactions():
f"No transactions found. <a href='{url_for('admin.transactions')}'>View all transactions</a>" # noqa: E501
)
flash(msg)

return render_template(
"admin/transactions.html",
transactions=query.paginate(page=page, per_page=10),
Expand Down
169 changes: 33 additions & 136 deletions subscribie/blueprints/admin/templates/admin/subscribers.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "admin/layout.html" %}
{% import "macros/subscribers-plan-macro.html" as plan_template %}
{% block title %} Subscribers {% endblock %}

{% block body %}
Expand Down Expand Up @@ -84,124 +85,23 @@ <h4>Search...</h4>
<li>
<div class="card">
<ul class="list-unstyled px-2">
<li><strong>Title: </strong>
<span class="subscription-title">{{ subscription.plan.title }}</span>
</li>
<li>
<strong>Interval:</strong>
{% if subscription.plan is not sameas None and subscription.plan.interval_unit is not sameas None %}
{{ subscription.plan.interval_unit.capitalize() }}
{% else %}
{{ subscription.plan.interval_unit }}
{% endif %}
</li>
{{ plan_template.subscriber_plan_title(subscription.title, "subscription_title") }}
{{ plan_template.subscriber_plan_interval(subscription.plan) }}
{% if subscription.chosen_options %}
<li>
<details open>
<summary><strong>Chosen Options</strong></summary>
<ul>
{% for choice in subscription.chosen_options %}
<li><strong>{{ choice.choice_group_title }}:</strong> {{ choice.option_title }}</li>
{% endfor %}
</ul>
</details>
</li>
{{ plan_template.subscriber_plan_chosen_options(subscription.chosen_options) }}
{% endif %}
<li><strong>Subscription ID: </strong>{{ subscription.uuid }}</li>
<li><strong>Date started: </strong>{{ subscription.created_at.strftime('%Y-%m-%d') }}</li>
<li>
{% if subscription.plan.requirements and subscription.plan.requirements.subscription %}
<strong>Price: </strong>
<span class="subscribers-plan-interval_amount">{{ subscription.showIntervalAmount() }}</span>
{% else %}
(One-off. Not a subscription)
{% endif %}
</li>
<li><strong>Sell price: </strong>
<span class="subscribers-plan-sell-price">
{% if subscription.plan.requirements and subscription.plan.requirements.instant_payment %}
{{ subscription.showSellPrice() }}</li>
{% else %}
(No up-front fee)
{% endif %}
</span>
<li><strong>Status:</strong>
{% if subscription.plan.requirements and subscription.plan.requirements.subscription %}
{% if subscription.stripe_pause_collection == "void" %}
<span class="subscription-status">Paused</span>
{% else %}
<span class="subscription-status">{{ subscription.stripe_status }}</span>
{% endif %}
{% else %}
<span class="subscription-status">Paid</span>
{% endif %}
</li>
{% if subscription.stripe_cancel_at %}
<strong>Automatically Cancels at:</strong>
{{ subscription.stripe_cancel_at | timestampToDate }}
{% endif %}
<li>
</li>
<li>
{% if subscription.plan.requirements and subscription.plan.requirements.note_to_seller_required %}
<details open>
<summary><strong>Order Note</strong></summary>
{% if subscription.note %}
{{ subscription.note.note }}
{% else %}
No note was given.
{% endif %}
</details>
{% endif %}
</li>
<li><strong>Actions: </strong>
{% if subscription.plan.requirements and subscription.plan.requirements.subscription %}
{% if subscription.stripe_status|lower in ['active', 'trialing', 'past_due', 'unpaid'] %}
{% if subscription.stripe_status|lower != 'trialing' and subscription.stripe_pause_collection != 'void' %}
<a href="{{ url_for("admin.pause_stripe_subscription",
subscription_id=subscription.stripe_subscription_id,
confirm="") }}">
<span class="pause-action">Pause</span>
</a> |
<a href="{{ url_for("admin.cancel_stripe_subscription",
subscription_id=subscription.stripe_subscription_id,
confirm="") }}">
<span class="cancel-action">Cancel</span>
</a> |
{% endif %}
{% endif %}
{% if subscription.stripe_pause_collection|lower == 'void' %}
<a href="{{ url_for("admin.resume_stripe_subscription",
subscription_id=subscription.stripe_subscription_id,
confirm="") }}">
<span class="resume-action">Resume</span>
</a> |
<a href="{{ url_for("admin.cancel_stripe_subscription",
subscription_id=subscription.stripe_subscription_id,
confirm="") }}">
<span class="cancel-action">Cancel</span>
</a> |
{% endif %}
{% endif %}</li>
<li class=mt-2><strong>History: </strong>
<a href="{{ url_for('admin.transactions',
subscriber=subscription.person.uuid) }}">View Transactions
</a>
</li>
<li class=mt-2><strong>Documents: </strong>
{% if subscription.documents|length == 0 %}
None
{% else %}
<ul>
{% for document in subscription.documents %}
{# Show documents assocated with subscription (if any) #}
<li><a href="{{ url_for('document.show_document', document_uuid=document.uuid) }}">
{{ document.name }}</a> |
{{ document.created_at.strftime('%Y-%m-%d') }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{{ plan_template.subscriber_plan_subscription_id("Subscription ID", subscription.uuid) }}
{{ plan_template.subscriber_plan_started_date(subscription.created_at) }}
{{ plan_template.subscriber_plan_interval_amount(subscription.plan.requirements, subscription) }}
{{ plan_template.subscriber_plan_sell_price("Sell price", "subscribers-plan-sell-price", subscription, transaction | default(null)) }}
{{ plan_template.subscriber_plan_status("subscription-status",subscription, transaction | default(null)) }}
{% if subscription.stripe_cancel_at %}
{{ plan_template.subscriber_plan_cancel_at(subscription.stripe_cancel_at) }}
{% endif %}
{{ plan_template.subscriber_plan_order_note(subscription.plan.requirements, subscription) }}
{{ plan_template.subscriber_plan_actions(subscription.plan.requirements, subscription) }}
{{ plan_template.subscriber_plan_history(subscription.person.uuid) }}
{{ plan_template.subscriber_plan_documents(subscription.documents) }}
</ul>
</div>
</li>
Expand All @@ -214,29 +114,26 @@ <h4>Search...</h4>
{% if transaction.is_donation %}
<div class="card">
<ul class="list-unstyled px-2">
<li><strong>Title: </strong>
<span class="donation-title">Donation</span>
</li>
<li><strong>Transaction ID: </strong>{{ transaction.uuid }}</li>
<li><strong>Date: </strong>{{ transaction.created_at.strftime('%Y-%m-%d') }}</li>
{{ plan_template.subscriber_plan_title("Donation", "subscription_title") }}
{{ plan_template.subscriber_plan_subscription_id("Transaction ID", transaction.uuid) }}
{{ plan_template.subscriber_plan_started_date(transaction.created_at) }}
{{ plan_template.subscriber_plan_sell_price("Donation amount", "donation_amount", subscription | default(null), transaction) }}
{{ plan_template.subscriber_plan_status("transaction-status",subscription | default(null), transaction.payment_status) }}
{{ plan_template.subscriber_transaction_comment("Donation Note", transaction.comment) }}
</ul>
</div>
{% elif transaction.payment_status != 'succeeded' %}
<div class="card">
<ul class="list-unstyled px-2">
{{ plan_template.subscriber_plan_title("Failed Payment", "failed-payment-title") }}
{{ plan_template.subscriber_plan_subscription_id("Transaction ID", transaction.uuid) }}
{{ plan_template.subscriber_plan_started_date(transaction.created_at) }}
<li>
<strong>Price: </strong>
<span class="donation_amount">{{ transaction.showSellPrice() }}</span>
<span class="failed-payment-amount">{{ transaction.showSellPrice() }}</span>
{{ plan_template.subscriber_plan_sell_price("Price", "failed-payment-amount", subscription | default(null), transaction) }}
</li>
</span>
<li><strong>Status:</strong>
<span class="transaction-status">{{ transaction.payment_status }}</span>
</li>
<li>
{% if transaction.comment %}
<details open>
<summary><strong>Donation Note</strong></summary>
{{ transaction.comment }}
{% else %}
No note was given.
</details>
{% endif %}
</li>
{{ plan_template.subscriber_plan_status("failed-payment-status",subscription | default(null), transaction.payment_status) }}
</ul>
</div>
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ <h1>All Transactions ({{ transactions.total }})</h1>
</td>
<td>
<!-- if there is a external_refund id then don't show refund button -->
{% if transaction.external_refund_id is sameas None %}
{% if transaction.external_refund_id is sameas None and transaction.payment_status == 'paid' %}
<a class="refund-action" href="{{ url_for('admin.refund_stripe_subscription', payment_id=transaction.external_id, confirm="") }}">Refund</a>

{% endif %}
Expand Down
Loading