You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.8 KiB

9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
7 years ago
7 years ago
7 years ago
  1. from io import BytesIO
  2. from django.conf import settings
  3. from django.contrib import messages
  4. from django.contrib.auth.decorators import login_required
  5. from django.http import (
  6. HttpResponseBadRequest,
  7. HttpResponseForbidden,
  8. JsonResponse,
  9. HttpResponse,
  10. )
  11. from django.shortcuts import get_object_or_404, redirect, render
  12. from django.views.decorators.csrf import csrf_exempt
  13. from django.views.decorators.http import require_POST
  14. from hc.api.models import Check
  15. from hc.lib import emails
  16. from hc.payments.forms import InvoiceEmailingForm
  17. from hc.payments.invoices import PdfInvoice
  18. from hc.payments.models import Subscription
  19. @login_required
  20. def get_client_token(request):
  21. sub = Subscription.objects.for_user(request.user)
  22. return JsonResponse({"client_token": sub.get_client_token()})
  23. def pricing(request):
  24. if request.user.is_authenticated and request.user != request.project.owner:
  25. ctx = {"page": "pricing"}
  26. return render(request, "payments/pricing_not_owner.html", ctx)
  27. # Don't use Subscription.objects.for_user method here, so a
  28. # subscription object is not created just by viewing a page.
  29. sub = Subscription.objects.filter(user_id=request.user.id).first()
  30. ctx = {
  31. "page": "pricing",
  32. "sub": sub,
  33. "enable_whatsapp": settings.TWILIO_USE_WHATSAPP,
  34. }
  35. return render(request, "payments/pricing.html", ctx)
  36. @login_required
  37. def billing(request):
  38. # Don't use Subscription.objects.for_user method here, so a
  39. # subscription object is not created just by viewing a page.
  40. sub = Subscription.objects.filter(user_id=request.user.id).first()
  41. if sub is None:
  42. sub = Subscription(user=request.user)
  43. send_invoices_status = "default"
  44. if request.method == "POST":
  45. form = InvoiceEmailingForm(request.POST)
  46. if form.is_valid():
  47. sub = Subscription.objects.for_user(request.user)
  48. form.update_subscription(sub)
  49. send_invoices_status = "success"
  50. ctx = {
  51. "page": "billing",
  52. "profile": request.profile,
  53. "sub": sub,
  54. "num_checks": Check.objects.filter(project__owner=request.user).count(),
  55. "send_invoices_status": send_invoices_status,
  56. "set_plan_status": "default",
  57. "address_status": "default",
  58. "payment_method_status": "default",
  59. }
  60. if "set_plan_status" in request.session:
  61. ctx["set_plan_status"] = request.session.pop("set_plan_status")
  62. if "address_status" in request.session:
  63. ctx["address_status"] = request.session.pop("address_status")
  64. if "payment_method_status" in request.session:
  65. ctx["payment_method_status"] = request.session.pop("payment_method_status")
  66. return render(request, "accounts/billing.html", ctx)
  67. def log_and_bail(request, result):
  68. logged_deep_error = False
  69. for error in result.errors.deep_errors:
  70. messages.error(request, error.message)
  71. logged_deep_error = True
  72. if not logged_deep_error:
  73. messages.error(request, result.message)
  74. return redirect("hc-billing")
  75. @login_required
  76. @require_POST
  77. def set_plan(request):
  78. plan_id = request.POST["plan_id"]
  79. if plan_id not in ("", "P20", "P80", "Y192", "Y768"):
  80. return HttpResponseBadRequest()
  81. sub = Subscription.objects.for_user(request.user)
  82. if sub.plan_id == plan_id:
  83. return redirect("hc-billing")
  84. # Cancel the previous plan
  85. sub.cancel()
  86. if plan_id == "":
  87. profile = request.user.profile
  88. profile.ping_log_limit = 100
  89. profile.check_limit = 20
  90. profile.team_limit = 2
  91. profile.sms_limit = 0
  92. profile.save()
  93. return redirect("hc-billing")
  94. result = sub.setup(plan_id)
  95. if not result.is_success:
  96. return log_and_bail(request, result)
  97. # Update user's profile
  98. profile = request.user.profile
  99. if plan_id in ("P20", "Y192"):
  100. profile.ping_log_limit = 1000
  101. profile.check_limit = 100
  102. profile.team_limit = 9
  103. profile.sms_limit = 50
  104. profile.sms_sent = 0
  105. profile.save()
  106. elif plan_id in ("P80", "Y768"):
  107. profile.ping_log_limit = 1000
  108. profile.check_limit = 1000
  109. profile.team_limit = 500
  110. profile.sms_limit = 500
  111. profile.sms_sent = 0
  112. profile.save()
  113. request.session["set_plan_status"] = "success"
  114. return redirect("hc-billing")
  115. @login_required
  116. def address(request):
  117. sub = Subscription.objects.for_user(request.user)
  118. if request.method == "POST":
  119. error = sub.update_address(request.POST)
  120. if error:
  121. return log_and_bail(request, error)
  122. request.session["address_status"] = "success"
  123. return redirect("hc-billing")
  124. ctx = {"a": sub.address, "email": request.user.email}
  125. return render(request, "payments/address.html", ctx)
  126. @login_required
  127. def payment_method(request):
  128. sub = get_object_or_404(Subscription, user=request.user)
  129. if request.method == "POST":
  130. if "payment_method_nonce" not in request.POST:
  131. return HttpResponseBadRequest()
  132. nonce = request.POST["payment_method_nonce"]
  133. error = sub.update_payment_method(nonce)
  134. if error:
  135. return log_and_bail(request, error)
  136. request.session["payment_method_status"] = "success"
  137. return redirect("hc-billing")
  138. ctx = {"sub": sub, "pm": sub.payment_method}
  139. return render(request, "payments/payment_method.html", ctx)
  140. @login_required
  141. def billing_history(request):
  142. try:
  143. sub = Subscription.objects.get(user=request.user)
  144. transactions = sub.transactions
  145. except Subscription.DoesNotExist:
  146. transactions = []
  147. ctx = {"transactions": transactions}
  148. return render(request, "payments/billing_history.html", ctx)
  149. @login_required
  150. def pdf_invoice(request, transaction_id):
  151. sub, tx = Subscription.objects.by_transaction(transaction_id)
  152. # Does this transaction belong to a customer we know about?
  153. if sub is None or tx is None:
  154. return HttpResponseForbidden()
  155. # Does the transaction's customer match the currently logged in user?
  156. if sub.user != request.user and not request.user.is_superuser:
  157. return HttpResponseForbidden()
  158. response = HttpResponse(content_type="application/pdf")
  159. filename = "MS-HC-%s.pdf" % tx.id.upper()
  160. response["Content-Disposition"] = 'attachment; filename="%s"' % filename
  161. PdfInvoice(response).render(tx, sub.flattened_address())
  162. return response
  163. @csrf_exempt
  164. @require_POST
  165. def charge_webhook(request):
  166. sub, tx = Subscription.objects.by_braintree_webhook(request)
  167. if sub.send_invoices:
  168. filename = "MS-HC-%s.pdf" % tx.id.upper()
  169. sink = BytesIO()
  170. PdfInvoice(sink).render(tx, sub.flattened_address())
  171. ctx = {"tx": tx}
  172. recipient = sub.invoice_email or sub.user.email
  173. emails.invoice(recipient, ctx, filename, sink.getvalue())
  174. return HttpResponse()