Improve subscr cancellation, add unusub feedback

master
Alice 5 years ago
parent 3a99cf850d
commit b3539ef829

@ -232,6 +232,9 @@ PAYMENTS_BACKENDS = {
# 'receiver': '', # PayPal primary address if different
# 'currency': 'EUR',
# 'header_image': '',
'api_username': ',
'api_password': '',
'api_sig': '',
},
'stripe': {
'enabled': False,

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-23 02:40+0000\n"
"POT-Creation-Date: 2019-09-07 21:02+0000\n"
"PO-Revision-Date: 2016-04-07 01:32+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
@ -264,19 +264,19 @@ msgstr "Config"
msgid "Status"
msgstr "État"
#: payments/admin.py:11
#: payments/admin.py:12
msgid "Mark as cancelled (do not actually cancel)"
msgstr "Marquer comme annulé (n'annule pas)"
#: payments/admin.py:36 payments/admin.py:91
#: payments/admin.py:37 payments/admin.py:92
msgid "Payment Data"
msgstr "Données de paiement"
#: payments/admin.py:59
#: payments/admin.py:60
msgid "Amount"
msgstr "Montant"
#: payments/admin.py:63
#: payments/admin.py:64
msgid "Paid amount"
msgstr "Montant payé"
@ -351,11 +351,11 @@ msgstr ""
"En attente de la confirmation par Paypal... Cette étape peut durer quelques "
"minutes..."
#: payments/backends/paypal.py:13 payments/backends/paypal.py:14
#: payments/backends/paypal.py:14 payments/backends/paypal.py:15
msgid "PayPal"
msgstr "PayPal"
#: payments/backends/paypal.py:51
#: payments/backends/paypal.py:59
msgid ""
"Waiting for PayPal to confirm the transaction... It can take up to a few "
"minutes..."
@ -416,20 +416,17 @@ msgid "Every year"
msgstr "Tous les ans"
#: payments/views.py:156
msgid ""
"Error subscribing. It usually means you don't have enough money available."
msgstr ""
"Il y a une erreur à l'inscription. C'est le plus souvent un manque de fonds "
"sur la carte."
#: payments/views.py:159
msgid "Subscribed!"
msgstr "Abonné!"
#: payments/views.py:197
msgid "Subscription cancelled!"
msgstr "Abonnement annulé!"
#: payments/views.py:158
msgid ""
"Could not cancel the subscription. It may have already been cancelled or "
"caused an error."
msgstr ""
"Impossible d'annuler le paiement récurrent. Il a peut-être été déjà annulé "
"ou une erreur est survenue."
#: templates/account_layout.html:12
msgid "Config Download"
msgstr "Configuration"
@ -443,7 +440,7 @@ msgstr "Paiements"
msgid "Models in the %(name)s application"
msgstr ""
#: templates/admin/index.html:31 templates/lambdainst/account.html:148
#: templates/admin/index.html:31 templates/lambdainst/account.html:128
msgid "Add"
msgstr "Ajouter"
@ -676,19 +673,11 @@ msgstr ""
"Votre compte est actif. Votre abonnement sera automatiquement renouvelé le "
"%(until)s via %(backend)s."
#: templates/lambdainst/account.html:28
msgid "You can cancel it from PayPal account."
msgstr "Vous pouvez annuler depuis votre compte PayPal."
#: templates/lambdainst/account.html:35
msgid "Cancel Subscription"
msgstr "Annuler l'abonnement"
#: templates/lambdainst/account.html:26
msgid "cancel"
msgstr "annuler"
#: templates/lambdainst/account.html:43
msgid "Do you really want to cancel your subscription?"
msgstr "Voulez-vous vraimer annuler votre abonnement ?"
#: templates/lambdainst/account.html:50
#: templates/lambdainst/account.html:30
#, python-format
msgid ""
"Your subscription is waiting for confirmation by %(backend)s. It may take up "
@ -697,17 +686,17 @@ msgstr ""
"Votre abonnement est en attente de confirmation par %(backend)s. Cette étape "
"peut prendre jusqu'à quelques minutes..."
#: templates/lambdainst/account.html:58
#: templates/lambdainst/account.html:38
#, python-format
msgid "Your account is paid until %(until)s"
msgstr "Votre compte est activé jusqu'au %(until)s"
#: templates/lambdainst/account.html:61
#: templates/lambdainst/account.html:41
#, python-format
msgid "(%(left)s left)"
msgstr "(%(left)s restant)"
#: templates/lambdainst/account.html:67
#: templates/lambdainst/account.html:47
msgid ""
"You can activate your free trial account for two hours periods for up to one "
"week, by clicking this button:"
@ -715,75 +704,75 @@ msgstr ""
"Vous pouvez activez votre compte d'essai pour des périodes de deux heures "
"pendant jusqu'à une semaine avec ce bouton:"
#: templates/lambdainst/account.html:76
#: templates/lambdainst/account.html:56
msgid "Activate"
msgstr "Activer"
#: templates/lambdainst/account.html:93
#: templates/lambdainst/account.html:73
msgid "Your account is not paid."
msgstr "Votre compte n'est pas payé."
#: templates/lambdainst/account.html:102 templates/payments/list.html:6
#: templates/lambdainst/account.html:82 templates/payments/list.html:6
msgid "Subscription"
msgstr "Abonnement"
#: templates/lambdainst/account.html:110
#: templates/lambdainst/account.html:90
msgid "Pay every"
msgstr "Payer tous les"
#: templates/lambdainst/account.html:112 templates/lambdainst/account.html:113
#: templates/lambdainst/account.html:114 templates/lambdainst/account.html:151
#: templates/lambdainst/account.html:152 templates/lambdainst/account.html:153
#: templates/lambdainst/account.html:92 templates/lambdainst/account.html:93
#: templates/lambdainst/account.html:94 templates/lambdainst/account.html:131
#: templates/lambdainst/account.html:132 templates/lambdainst/account.html:133
msgid "months"
msgstr "mois"
#: templates/lambdainst/account.html:119 templates/lambdainst/account.html:158
#: templates/lambdainst/account.html:99 templates/lambdainst/account.html:138
msgid "by"
msgstr "par"
#: templates/lambdainst/account.html:131
#: templates/lambdainst/account.html:111
msgid "Subscribe"
msgstr "S'abonner"
#: templates/lambdainst/account.html:133
#: templates/lambdainst/account.html:113
msgid "You can cancel the recurring payment at any time."
msgstr "Vous pouvez annuler le paiement récurrent à n'importe quel moment."
#: templates/lambdainst/account.html:140
#: templates/lambdainst/account.html:120
msgid "One-time payment"
msgstr "Paiement ponctuel"
#: templates/lambdainst/account.html:150
#: templates/lambdainst/account.html:130
msgid "month"
msgstr "mois"
#: templates/lambdainst/account.html:170
#: templates/lambdainst/account.html:150
msgid "Buy Now"
msgstr "Acheter"
#: templates/lambdainst/account.html:172
#: templates/lambdainst/account.html:152
msgid "If you still have time, it will be added."
msgstr "S'il vous reste du temps, il sera ajouté."
#: templates/lambdainst/account.html:183
#: templates/lambdainst/account.html:163
msgid "Gift code"
msgstr "Code cadeau"
#: templates/lambdainst/account.html:189
#: templates/lambdainst/account.html:169
msgid "Redeem gift code"
msgstr "Récupérer le code cadeau"
#: templates/lambdainst/account.html:199
#: templates/lambdainst/account.html:179
msgid ""
"Get two weeks for free for every referral that takes at least one month!"
msgstr ""
"Gagnez deux semaines gratuites pour chaque client qui a utilisé ce lien !"
#: templates/lambdainst/account.html:202
#: templates/lambdainst/account.html:182
msgid "Share this link"
msgstr "Partagez ce lien"
#: templates/lambdainst/account.html:206
#: templates/lambdainst/account.html:186
msgid "tweet"
msgstr ""
@ -895,7 +884,7 @@ msgstr "IP Partagée"
msgid "Bandwidth"
msgstr "Bande passante"
#: templates/lambdainst/logs.html:27 tickets/admin.py:50 tickets/models.py:58
#: templates/lambdainst/logs.html:27 tickets/admin.py:50 tickets/models.py:57
msgid "Open"
msgstr "Open"
@ -1000,7 +989,7 @@ msgid "Guides"
msgstr "Guides"
#: templates/layout.html:57 templates/tickets/index.html:6
#: templates/tickets/layout.html:8 tickets/models.py:14
#: templates/tickets/layout.html:8 tickets/models.py:13
msgid "Support"
msgstr "Support"
@ -1032,6 +1021,23 @@ msgstr "C'est open-source!"
msgid "Any question? <b>Chat with us</b>"
msgstr "Une question ? <b>Contactez nous</b>"
#: templates/payments/cancel_subscr.html:8
#: templates/payments/cancel_subscr.html:24
msgid "Cancel Subscription"
msgstr "Annuler l'abonnement"
#: templates/payments/cancel_subscr.html:15
msgid "We're sorry to see you go."
msgstr "Nous sommes désolés que vous nous quittiez."
#: templates/payments/cancel_subscr.html:16
msgid ""
"Would you like to tell us why, or leave any feedback so we can improve our "
"service?"
msgstr ""
"Voudriez-vous nous dire pourquoi, ou laisser un retour pour nous permettre "
"d'améliorer notre service ?"
#: templates/payments/form.html:7 templates/payments/view.html:13
msgid "Payment"
msgstr "Paiement"
@ -1188,7 +1194,7 @@ msgstr "Nouvelle réponse à votre ticket:"
msgid "Open Ticket"
msgstr "Créer le ticket"
#: templates/tickets/view.html:7 tickets/models.py:66 tickets/models.py:72
#: templates/tickets/view.html:7 tickets/models.py:65 tickets/models.py:71
#: tickets/views.py:116 tickets/views.py:146
msgid "Ticket:"
msgstr "Ticket:"
@ -1221,7 +1227,7 @@ msgstr "Fermer les tickets séléctionnés"
msgid "Re-opened"
msgstr "Ré-ouvert"
#: tickets/admin.py:52 tickets/models.py:53
#: tickets/admin.py:52 tickets/models.py:52
msgid "Closed"
msgstr "Fermé"
@ -1233,30 +1239,45 @@ msgstr "Catégorie"
msgid "Message"
msgstr "Message"
#: tickets/models.py:15
#: tickets/models.py:14
msgid "Security"
msgstr "Sécurité"
#: tickets/models.py:16
#: tickets/models.py:15
msgid "Account / Billing"
msgstr "Compte / Facturation"
#: tickets/models.py:36
#: tickets/models.py:35
msgid "Can view any ticket"
msgstr "Peut voir n'importe quel ticket"
#: tickets/models.py:37
#: tickets/models.py:36
msgid "Can reply to any ticket"
msgstr "Peut répondre à n'importe quel ticket"
#: tickets/models.py:38
#: tickets/models.py:37
msgid "Can view private messages on tickets"
msgstr "Peut voir les messages privés"
#: tickets/models.py:39
#: tickets/models.py:38
msgid "Can post private messages on tickets"
msgstr "Peut envoyer des messages privés"
#: tickets/models.py:56
#: tickets/models.py:55
msgid "Waiting for staff"
msgstr "En attente du support"
#~ msgid ""
#~ "Error subscribing. It usually means you don't have enough money available."
#~ msgstr ""
#~ "Il y a une erreur à l'inscription. C'est le plus souvent un manque de "
#~ "fonds sur la carte."
#~ msgid "Subscribed!"
#~ msgstr "Abonné!"
#~ msgid "You can cancel it from PayPal account."
#~ msgstr "Vous pouvez annuler depuis votre compte PayPal."
#~ msgid "Do you really want to cancel your subscription?"
#~ msgstr "Voulez-vous vraimer annuler votre abonnement ?"

@ -3,7 +3,8 @@ from django.shortcuts import resolve_url
from django.contrib import admin
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _
from .models import Payment, Subscription
from django.utils.text import Truncator
from .models import Payment, Subscription, Feedback
def subscr_mark_as_cancelled(modeladmin, request, queryset):
@ -116,6 +117,15 @@ class SubscriptionAdmin(admin.ModelAdmin):
return link(object.backend_extid, ext_url)
backend_extid_link.allow_tags = True
class FeedbackAdmin(admin.ModelAdmin):
model = Feedback
list_display = ('user', 'created', 'short_message')
readonly_fields = ('user', 'created', 'message', 'subscription')
def short_message(self, obj):
return Truncator(obj.message).chars(80)
admin.site.register(Payment, PaymentAdmin)
admin.site.register(Subscription, SubscriptionAdmin)
admin.site.register(Feedback, FeedbackAdmin)

@ -4,6 +4,7 @@ from urllib.parse import urlencode
from urllib.request import urlopen
from django.urls import reverse
from django.conf import settings as project_settings
import requests
from .base import BackendBase
@ -22,13 +23,20 @@ class PaypalBackend(BackendBase):
self.account_address = settings.get('address')
self.receiver_address = settings.get('receiver', self.account_address)
self.api_username = settings.get('api_username')
self.api_password = settings.get('api_password')
self.api_sig = settings.get('api_sig')
if self.test:
default_nvp = 'https://api-3t.sandbox.paypal.com/nvp'
default_api = 'https://www.sandbox.paypal.com/'
else:
default_nvp = 'https://api-3t.paypal.com/nvp'
default_api = 'https://www.paypal.com/'
self.api_base = settings.get('api_base', default_api)
self.nvp_api_base = settings.get('nvp_api_base', default_nvp)
if self.account_address:
if self.account_address and self.api_username and self.api_password and self.api_sig:
self.backend_enabled = True
def new_payment(self, payment):
@ -196,6 +204,30 @@ class PaypalBackend(BackendBase):
subscr.save()
raise
def cancel_subscription(self, subscr):
if not subscr.backend_extid:
return False
try:
r = requests.post(self.nvp_api_base, data={
"METHOD": "ManageRecurringPaymentsProfileStatus",
"PROFILEID": subscr.backend_extid,
"ACTION": "cancel",
"USER": self.api_username,
"PWD": self.api_password,
"SIGNATURE": self.api_sig,
"VERSION": "204.0",
})
r.raise_for_status()
print(r.text)
subscr.status = 'cancelled'
subscr.save()
return True
except Exception as e:
print(e)
return False
def get_ext_url(self, payment):
if not payment.backend_extid:
return None

@ -123,6 +123,7 @@ class StripeBackend(BackendBase):
subscr.status = 'cancelled'
subscr.save()
return True
def webhook_session_completed(self, event):
session = event['data']['object']

@ -0,0 +1,26 @@
# Generated by Django 2.2.1 on 2019-09-07 20:29
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('payments', '0005_auto_20160907_0018'),
]
operations = [
migrations.CreateModel(
name='Feedback',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('message', models.TextField()),
('subscription', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='payments.Subscription')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

@ -55,11 +55,10 @@ ACTIVE_BACKEND_CHOICES = []
logger.info("loading payment backends...")
for cls in BACKEND_CLASSES:
name = cls.backend_id
prefix = "Backend {:<8}:".format(name)
assert isinstance(name, str)
if name not in backends_settings:
logger.info("%s disabled (no settings)", prefix)
logger.info("payments: ☐ %s disabled (no settings)", name)
continue
backend_settings = backends_settings.get(name, {})
@ -68,7 +67,7 @@ for cls in BACKEND_CLASSES:
backend_settings[k] = v()
if not backend_settings.get('enabled'):
logger.info("%s disabled (by settings)", prefix)
logger.info("payments: ☐ %s disabled (by settings)", name)
continue
obj = cls(backend_settings)
@ -79,14 +78,14 @@ for cls in BACKEND_CLASSES:
if obj.backend_enabled:
ACTIVE_BACKENDS[name] = obj
ACTIVE_BACKEND_CHOICES.append((name, cls.backend_verbose_name))
logger.info("%s ☑ initialized", prefix)
logger.info("payments: ☑ %s initialized", name)
else:
logger.info("%s disabled (initialization failed)", prefix)
logger.info("payments: ☒ %s disabled (initialization failed)", name)
BACKEND_CHOICES = sorted(BACKEND_CHOICES, key=lambda x: x[0])
ACTIVE_BACKEND_CHOICES = sorted(ACTIVE_BACKEND_CHOICES, key=lambda x: x[0])
logger.info("finished. %d/%d backends active", len(ACTIVE_BACKENDS), len(BACKEND_CLASSES))
logger.info("payments: finished. %d/%d backends active", len(ACTIVE_BACKENDS), len(BACKEND_CLASSES))
def period_months(p):
@ -221,3 +220,9 @@ class Subscription(models.Model):
return payment
class Feedback(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
subscription = models.ForeignKey('Subscription', null=True, blank=True, on_delete=models.SET_NULL)
created = models.DateTimeField(auto_now_add=True)
message = models.TextField()

@ -7,16 +7,15 @@ urlpatterns = [
url(r'^new$', views.new),
url(r'^view/(?P<id>[0-9]+)$', views.view, name='view'),
url(r'^cancel/(?P<id>[0-9]+)$', views.cancel, name='cancel'),
url(r'^cancel_subscr/(?P<id>[0-9]+)$', views.cancel_subscr, name='cancel_subscr'),
url(r'^cancel_subscr/(?P<id>[0-9]+)?$', views.cancel_subscr, name='cancel_subscr'),
url(r'^return_subscr/(?P<id>[0-9]+)$', views.return_subscr, name='return_subscr'),
url(r'^callback/paypal/(?P<id>[0-9]+)$', views.callback_paypal, name='cb_paypal'),
url(r'^callback/coingate/(?P<id>[0-9]+)$', views.callback_coingate, name='cb_coingate'),
url(r'^callback/stripe/(?P<id>[0-9]+)$', views.callback_stripe, name='cb_stripe'),
url(r'^callback/coinbase/$', views.callback_coinbase, name='cb_coinbase'),
url(r'^callback/coinpayments/(?P<id>[0-9]+)$', views.callback_coinpayments, name='cb_coinpayments'),
url(r'^callback/paypal_subscr/(?P<id>[0-9]+)$', views.callback_paypal_subscr, name='cb_paypal_subscr'),
url(r'^callback/stripe_subscr/(?P<id>[0-9]+)$', views.callback_stripe_subscr, name='cb_stripe_subscr'),
url(r'^callback/paypal/(?P<id>[0-9]+)$', views.payment_callback('paypal'), name='cb_paypal'),
url(r'^callback/coingate/(?P<id>[0-9]+)$', views.payment_callback('coingate'), name='cb_coingate'),
url(r'^callback/stripe/(?P<id>[0-9]+)$', views.payment_callback('stripe'), name='cb_stripe'),
url(r'^callback/coinbase/$', views.plain_callback('coinbase'), name='cb_coinbase'),
url(r'^callback/coinpayments/(?P<id>[0-9]+)$', views.payment_callback('coinpayments'), name='cb_coinpayments'),
url(r'^callback/paypal_subscr/(?P<id>[0-9]+)$', views.sub_callback('paypal'), name='cb_paypal_subscr'),
url(r'^callback/stripe_hook$', views.stripe_hook, name='stripe_hook'),

@ -10,7 +10,7 @@ from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from .forms import NewPaymentForm
from .models import Payment, Subscription, BACKENDS, ACTIVE_BACKENDS
from .models import Payment, Subscription, BACKENDS, ACTIVE_BACKENDS, Feedback
def require_backend(name):
@ -73,92 +73,45 @@ def new(request):
return r
def plain_callback(backend_name, method='callback'):
@csrf_exempt
def callback(request):
backend = require_backend(backend_name)
@csrf_exempt
def callback_paypal(request, id):
""" PayPal IPN """
backend = require_backend('paypal')
p = Payment.objects.get(id=id)
if backend.callback(p, request):
m = getattr(backend, method)
if m and m(Payment, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
return callback
@csrf_exempt
@login_required
def callback_stripe(request, id):
""" Stripe button POST """
backend = require_backend('stripe')
def payment_callback(backend_name):
@csrf_exempt
def callback(request, id):
backend = require_backend(backend_name)
p = Payment.objects.get(id=id)
backend.callback(p, request)
return redirect(reverse('payments:view', args=(id,)))
@csrf_exempt
def callback_coingate(request, id):
""" CoinGate payment callback """
backend = require_backend('coingate')
p = Payment.objects.get(id=id)
if backend.callback(p, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@csrf_exempt
def callback_coinbase(request):
backend = require_backend('coinbase')
if backend.callback(Payment, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@csrf_exempt
def callback_coinpayments(request, id):
""" CoinPayments payment callback """
backend = require_backend('coinpayments')
p = Payment.objects.get(id=id)
if backend.callback(p, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
return callback
@csrf_exempt
def callback_paypal_subscr(request, id):
""" PayPal Subscription IPN """
backend = require_backend('paypal')
def sub_callback(backend_name):
@csrf_exempt
def callback(request, id):
backend = require_backend(backend_name)
p = Subscription.objects.get(id=id)
if backend.callback_subscr(p, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@csrf_exempt
@login_required
def callback_stripe_subscr(request, id):
""" Stripe subscription form target """
backend = require_backend('stripe')
p = Subscription.objects.get(id=id)
backend.callback_subscr(p, request)
if p.status == 'error' or p.status == 'cancelled':
messages.add_message(request, messages.ERROR,
_("Error subscribing. It usually means you don't"
" have enough money available."))
else:
messages.add_message(request, messages.INFO, _("Subscribed!"))
return redirect(reverse('account:index'))
return callback
@csrf_exempt
def stripe_hook(request):
@ -187,18 +140,31 @@ def cancel(request, id):
@login_required
def cancel_subscr(request, id):
if request.method != 'POST':
return redirect('account:index')
def cancel_subscr(request, id=None):
if request.method == 'POST' and id:
p = Subscription.objects.get(id=id, user=request.user)
# Saving any feedback note
feedback = request.POST.get('feedback')
if feedback:
feedback = feedback[:10000]
f = Feedback(user=request.user, subscription=p, message=feedback)
f.save()
try:
p.backend.cancel_subscription(p)
if p.backend.cancel_subscription(p):
messages.add_message(request, messages.INFO, _("Subscription cancelled!"))
else:
messages.add_message(request, messages.ERROR, _("Could not cancel the subscription. It may have already been cancelled or caused an error."))
except NotImplementedError:
pass
return redirect('account:index')
subscription = request.user.vpnuser.get_subscription(include_unconfirmed=True)
return render(request, 'payments/cancel_subscr.html', {
'subscription': subscription,
})
@login_required
def return_subscr(request, id):
@ -217,4 +183,3 @@ def list_payments(request):
objects = request.user.payment_set.exclude(status='cancelled',
created__lte=cancelled_limit)
return render(request, 'payments/list.html', dict(payments=objects))

@ -300,6 +300,10 @@ a.pure-button-primary, a.pure-button-selected {
padding: 0.5em 2em;
}
.button-danger {
background-color: #A7332F;
}
form p.inputinfo {
font-size: 0.8em;
display: block;
@ -735,6 +739,20 @@ div.ticket-message-private {
}
/***************************************************/
/********************* Payments */
.payments-cancel-page hr {
margin: 2em 1em;
border-bottom: 0;
}
.payments-cancel-page .feedback {
width: 100%;
}
.payments-cancel-page .pure-controls {
text-align: center;
}
/***************************************************/
/********************* Live chat */

@ -23,28 +23,8 @@
{% blocktrans trimmed with until=subscription.next_renew|date:'DATE_FORMAT' backend=subscription.backend.backend_verbose_name %}
Your account is active. Your subscription will automatically renew on {{until}} ({{backend}}).
{% endblocktrans %}
(<a href="{% url 'payments:cancel_subscr' %}">{% trans "cancel" %}</a>)
</p>
{% if subscription.backend_id == 'paypal' %}
<p>{% trans 'You can cancel it from PayPal account.' %}</p>
{% else %}
<form action="/payments/cancel_subscr/{{subscription.id}}" method="post" class="pure-form centered-form" id="cancel-form">
{% csrf_token %}
<fieldset>
<div class="pure-controls">
<input type="submit" class="pure-button pure-button-primary"
value="{% trans 'Cancel Subscription' %}" />
</div>
</fieldset>
</form>
<script type="text/javascript">
(function() {
var e = document.getElementById("cancel-form");
e.onsubmit = function() {
return confirm("{% trans 'Do you really want to cancel your subscription?' %}");
};
})();
</script>
{% endif %}
{% else %}
<p class="account-status-paid">
{% blocktrans trimmed with backend=subscription.backend.backend_verbose_name %}

@ -0,0 +1,32 @@
{% extends 'account_layout.html' %}
{% load i18n %}
{% load staticfiles %}
{% block account_content %}
<div class="payments-cancel-page">
<h1>{% trans 'Cancel Subscription' %}</h1>
{% if subscription %}
<form action="/payments/cancel_subscr/{{subscription.id}}" method="post" class="pure-form centered-form" id="cancel-form">
{% csrf_token %}
<fieldset>
<p>
{% trans "We're sorry to see you go." %}<br />
{% trans "Would you like to tell us why, or leave any feedback so we can improve our service?" %}
</p>
<textarea name="feedback" class="pure-input-1" maxlength=10000></textarea>
<hr />
<div class="pure-controls">
<input type="submit" class="pure-button pure-button-primary button-danger"
value="{% trans 'Cancel Subscription' %}" />
</div>
</fieldset>
</form>
{% else %}
<p>You do not have any active subscription to cancel.</p>
{% endif %}
</div>
{% endblock %}
Loading…
Cancel
Save