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.

228 lines
7.1 KiB

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