@ -0,0 +1,16 @@ | |||||
from django import forms | |||||
from hc.accounts.forms import LowercaseEmailField | |||||
class InvoiceEmailingForm(forms.Form): | |||||
send_invoices = forms.IntegerField(min_value=0, max_value=2) | |||||
invoice_email = LowercaseEmailField(required=False) | |||||
def update_subscription(self, sub): | |||||
sub.send_invoices = self.cleaned_data["send_invoices"] > 0 | |||||
if self.cleaned_data["send_invoices"] == 2: | |||||
sub.invoice_email = self.cleaned_data["invoice_email"] | |||||
else: | |||||
sub.invoice_email = "" | |||||
sub.save() |
@ -0,0 +1,20 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Generated by Django 1.11.6 on 2018-04-21 15:23 | |||||
from __future__ import unicode_literals | |||||
from django.db import migrations, models | |||||
class Migration(migrations.Migration): | |||||
dependencies = [ | |||||
('payments', '0005_subscription_plan_name'), | |||||
] | |||||
operations = [ | |||||
migrations.AddField( | |||||
model_name='subscription', | |||||
name='invoice_email', | |||||
field=models.EmailField(blank=True, max_length=254), | |||||
), | |||||
] |
@ -1,16 +1,33 @@ | |||||
from mock import patch | |||||
from hc.payments.models import Subscription | from hc.payments.models import Subscription | ||||
from hc.test import BaseTestCase | from hc.test import BaseTestCase | ||||
class SetPlanTestCase(BaseTestCase): | |||||
class BillingCase(BaseTestCase): | |||||
@patch("hc.payments.models.braintree") | |||||
def test_it_saves_send_invoices_flag(self, mock): | |||||
def test_it_disables_invoice_emailing(self): | |||||
self.client.login(username="[email protected]", password="password") | self.client.login(username="[email protected]", password="password") | ||||
form = {"save_send_invoices": True} | |||||
form = {"send_invoices": "0"} | |||||
self.client.post("/accounts/profile/billing/", form) | self.client.post("/accounts/profile/billing/", form) | ||||
sub = Subscription.objects.get() | sub = Subscription.objects.get() | ||||
self.assertFalse(sub.send_invoices) | self.assertFalse(sub.send_invoices) | ||||
self.assertEqual(sub.invoice_email, "") | |||||
def test_it_enables_invoice_emailing(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"send_invoices": "1"} | |||||
self.client.post("/accounts/profile/billing/", form) | |||||
sub = Subscription.objects.get() | |||||
self.assertTrue(sub.send_invoices) | |||||
self.assertEqual(sub.invoice_email, "") | |||||
def test_it_saves_invoice_email(self): | |||||
self.client.login(username="[email protected]", password="password") | |||||
form = {"send_invoices": "2", "invoice_email": "[email protected]"} | |||||
self.client.post("/accounts/profile/billing/", form) | |||||
sub = Subscription.objects.get() | |||||
self.assertTrue(sub.send_invoices) | |||||
self.assertEqual(sub.invoice_email, "[email protected]") |
@ -0,0 +1,75 @@ | |||||
from mock import Mock, patch | |||||
from unittest import skipIf | |||||
from django.core import mail | |||||
from django.utils.timezone import now | |||||
from hc.payments.models import Subscription | |||||
from hc.test import BaseTestCase | |||||
try: | |||||
import reportlab | |||||
except ImportError: | |||||
reportlab = None | |||||
class ChargeWebhookTestCase(BaseTestCase): | |||||
def setUp(self): | |||||
super(ChargeWebhookTestCase, self).setUp() | |||||
self.sub = Subscription(user=self.alice) | |||||
self.sub.subscription_id = "test-id" | |||||
self.sub.customer_id = "test-customer-id" | |||||
self.sub.send_invoices = True | |||||
self.sub.save() | |||||
self.tx = Mock() | |||||
self.tx.id = "abc123" | |||||
self.tx.customer_details.id = "test-customer-id" | |||||
self.tx.created_at = now() | |||||
self.tx.currency_iso_code = "USD" | |||||
self.tx.amount = 5 | |||||
self.tx.subscription_details.billing_period_start_date = now() | |||||
self.tx.subscription_details.billing_period_end_date = now() | |||||
@skipIf(reportlab is None, "reportlab not installed") | |||||
@patch("hc.payments.views.Subscription.objects.by_braintree_webhook") | |||||
def test_it_works(self, mock_getter): | |||||
mock_getter.return_value = self.sub, self.tx | |||||
r = self.client.post("/pricing/charge/") | |||||
self.assertEqual(r.status_code, 200) | |||||
# See if email was sent | |||||
self.assertEqual(len(mail.outbox), 1) | |||||
msg = mail.outbox[0] | |||||
self.assertEqual(msg.subject, "Invoice from Mychecks") | |||||
self.assertEqual(msg.to, ["[email protected]"]) | |||||
self.assertEqual(msg.attachments[0][0], "MS-HC-ABC123.pdf") | |||||
@patch("hc.payments.views.Subscription.objects.by_braintree_webhook") | |||||
def test_it_obeys_send_invoices_flag(self, mock_getter): | |||||
mock_getter.return_value = self.sub, self.tx | |||||
self.sub.send_invoices = False | |||||
self.sub.save() | |||||
r = self.client.post("/pricing/charge/") | |||||
self.assertEqual(r.status_code, 200) | |||||
# It should not send the email | |||||
self.assertEqual(len(mail.outbox), 0) | |||||
@skipIf(reportlab is None, "reportlab not installed") | |||||
@patch("hc.payments.views.Subscription.objects.by_braintree_webhook") | |||||
def test_it_uses_invoice_email(self, mock_getter): | |||||
mock_getter.return_value = self.sub, self.tx | |||||
self.sub.invoice_email = "[email protected]" | |||||
self.sub.save() | |||||
r = self.client.post("/pricing/charge/") | |||||
self.assertEqual(r.status_code, 200) | |||||
# See if the email was sent to Alice's accountant: | |||||
self.assertEqual(len(mail.outbox), 1) | |||||
self.assertEqual(mail.outbox[0].to, ["[email protected]"]) |
@ -0,0 +1,8 @@ | |||||
#invoice-email { | |||||
margin-left: 50px; | |||||
width: 300px; | |||||
} | |||||
#invoice-emailing-status { | |||||
margin-right: 150px; | |||||
} |
@ -148,27 +148,24 @@ | |||||
<div class="panel panel-{{ send_invoices_status }}"> | <div class="panel panel-{{ send_invoices_status }}"> | ||||
<div class="panel-body settings-block"> | <div class="panel-body settings-block"> | ||||
<form method="post"> | |||||
{% csrf_token %} | |||||
<h2>Invoices to Email</h2> | |||||
<label class="checkbox-container"> | |||||
<input | |||||
name="send_invoices" | |||||
type="checkbox" | |||||
{% if sub.send_invoices %}checked{% endif %}> | |||||
<span class="checkmark"></span> | |||||
Send the invoice to {{ request.user.email }} | |||||
each time my payment method is successfully charged. | |||||
</label> | |||||
<button | |||||
type="submit" | |||||
name="save_send_invoices" | |||||
class="btn btn-default pull-right"> | |||||
Save Changes | |||||
</button> | |||||
</form> | |||||
<h2>Invoices to Email</h2> | |||||
<p id="invoice-emailing-status"> | |||||
{% if sub.send_invoices %} | |||||
Send the invoice to | |||||
{{ sub.invoice_email|default:request.user.email }} | |||||
each time my payment method is successfully charged. | |||||
{% else %} | |||||
Do not email invoices to me. | |||||
{% endif %} | |||||
</p> | |||||
<button | |||||
data-toggle="modal" | |||||
data-target="#invoice-emailing-modal" | |||||
class="btn btn-default pull-right"> | |||||
Change Preference | |||||
</button> | |||||
</div> | </div> | ||||
{% if send_invoices_status == "success" %} | {% if send_invoices_status == "success" %} | ||||
<div class="panel-footer"> | <div class="panel-footer"> | ||||
@ -447,6 +444,68 @@ | |||||
</form> | </form> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div id="invoice-emailing-modal" class="modal pm-modal"> | |||||
<div class="modal-dialog"> | |||||
<form method="post"> | |||||
{% csrf_token %} | |||||
<div class="modal-content"> | |||||
<div class="modal-header"> | |||||
<button type="button" class="close" data-dismiss="modal">×</button> | |||||
<h4>Invoices to Email</h4> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<label class="radio-container"> | |||||
<input | |||||
type="radio" | |||||
name="send_invoices" | |||||
value="0" | |||||
{% if not sub.send_invoices %} checked {% endif %}> | |||||
<span class="radiomark"></span> | |||||
Do not email invoices to me | |||||
</label> | |||||
<label class="radio-container"> | |||||
<input | |||||
type="radio" | |||||
name="send_invoices" | |||||
value="1" | |||||
{% if sub.send_invoices and not sub.invoice_email %} checked {% endif %}> | |||||
<span class="radiomark"></span> | |||||
Send invoices to {{ profile.user.email }} | |||||
</label> | |||||
<label class="radio-container"> | |||||
<input | |||||
type="radio" | |||||
name="send_invoices" | |||||
value="2" | |||||
{% if sub.send_invoices and sub.invoice_email %} checked {% endif %}> | |||||
<span class="radiomark"></span> | |||||
Send invoices to this email address: | |||||
</label> | |||||
<input | |||||
id="invoice-email" | |||||
name="invoice_email" | |||||
placeholder="[email protected]" | |||||
value="{{ sub.invoice_email }}" | |||||
type="email" | |||||
class="form-control" /> | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<button type="button" class="btn btn-default" data-dismiss="modal"> | |||||
Cancel | |||||
</button> | |||||
<button type="submit" class="btn btn-primary"> | |||||
Save Changes | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
{% endblock %} | {% endblock %} | ||||
{% block scripts %} | {% block scripts %} | ||||