From cf2be43bcc2aa7fddff96ce22e78525b7c700e69 Mon Sep 17 00:00:00 2001
From: Chad Whitacre
+
+{{ exchange.note }}
+
+
+{{ _("Fix your credit card") }}
+
+[---] text/plain
+{{ ngettext(
+ "We tried to charge your credit card {0} today, to fund your weekly payment to {1}, but it failed.",
+ "We tried to charge your credit card {0} today, to fund your weekly payments to {1}, but it failed.",
+ format_currency(exchange.amount, 'USD'),
+ top_tippee.username if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee.username)
+ ) }}
+
+{{ _("The error message we received from our payment processor is:") }}
+
+{{ exchange.note }}
+
+{{ _("Follow this link to fix your credit card:") }} {{ participant.profile_url+'routes/credit-card.html' }}
diff --git a/emails/verification.spt b/emails/verification.spt
index 880d38e0ab..c58eccb382 100644
--- a/emails/verification.spt
+++ b/emails/verification.spt
@@ -6,7 +6,7 @@
('{0}'|safe).format(username)) }}
-{{ _("Yes, proceed!") }}
+{{ _("Yes, proceed!") }}
[---] text/plain
{{ _("We've received a request to connect {0} to the {1} account on Gratipay. Sound familiar?",
diff --git a/gratipay/models/participant.py b/gratipay/models/participant.py
index 4b8f46e66f..5550bcd3ef 100644
--- a/gratipay/models/participant.py
+++ b/gratipay/models/participant.py
@@ -624,6 +624,11 @@ def remove_email(self, address):
def send_email(self, spt_name, **context):
context['username'] = self.username
+ context['button_style'] = (
+ "color: #fff; text-decoration:none; display:inline-block; "
+ "padding: 0 15px; background: #396; white-space: nowrap; "
+ "font: normal 14px/40px Arial, sans-serif; border-radius: 3px"
+ )
context.setdefault('include_unsubscribe', True)
email = context.setdefault('email', self.email_address)
langs = i18n.parse_accept_lang(self.email_lang or 'en')
From a64d3263fdcc0dd7b1e3c93540ee01aec6a6259f Mon Sep 17 00:00:00 2001
From: Changaco
- Send me notifications via email when: +
@@ -19,8 +20,9 @@ {{ ngettext( "We tried to charge your credit card {0} today, to fund your weekly payment to {1}, but it failed.", "We tried to charge your credit card {0} today, to fund your weekly payments to {1}, but it failed.", + ntippees, format_currency(exchange.amount, 'USD'), - top_tippee.username if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee.username) + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) ) }} {{ _("The error message we received from our payment processor is:") }} diff --git a/emails/charge_succeeded.spt b/emails/charge_succeeded.spt index b104c1812c..d05e26afbe 100644 --- a/emails/charge_succeeded.spt +++ b/emails/charge_succeeded.spt @@ -4,18 +4,20 @@ {{ ngettext( "We charged your credit card {0} today, to fund your weekly payment to {1}. Thanks for using Gratipay!", "We charged your credit card {0} today, to fund your weekly payments to {1}. Thanks for using Gratipay!", + ntippees, format_currency(exchange.amount, 'USD'), ('{1}'|safe).format( participant.profile_url+'giving/', - top_tippee.username if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee.username) + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) )) }} [---] text/plain {{ ngettext( "We charged your credit card {0} today, to fund your weekly payment to {1}. Thanks for using Gratipay!", "We charged your credit card {0} today, to fund your weekly payments to {1}. Thanks for using Gratipay!", + ntippees, format_currency(exchange.amount, 'USD'), - top_tippee.username if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee.username) + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) ) }} {{ _("Follow this link if you want to view or modify your payments:") }} {{ participant.profile_url+'giving/' }} diff --git a/gratipay/billing/payday.py b/gratipay/billing/payday.py index 99ea9d40e6..94dade64cf 100644 --- a/gratipay/billing/payday.py +++ b/gratipay/billing/payday.py @@ -729,13 +729,13 @@ def notify_participants(self): username = p.username ntippees, top_tippee = self.db.one(""" WITH tippees AS ( - SELECT p.*::participants + SELECT p.username, amount FROM ( SELECT DISTINCT ON (tippee) tippee, amount FROM tips WHERE mtime < %(ts_start)s AND tipper = %(username)s ORDER BY tippee, mtime DESC - ) + ) t JOIN participants p ON p.username = t.tippee WHERE t.amount > 0 AND (p.goal IS NULL or p.goal >= 0) @@ -743,16 +743,15 @@ def notify_participants(self): AND p.claimed_time < %(ts_start)s ) SELECT ( SELECT count(*) FROM tippees ) AS ntippees - , ( SELECT t.* - FROM tippees t + , ( SELECT username + FROM tippees ORDER BY amount DESC LIMIT 1 ) AS top_tippee """, locals()) p.queue_email( 'charge_'+e.status, - exchange=e, - participant=p, + exchange=dict(amount=e.amount, fee=e.fee, note=e.note), ntippees=ntippees, top_tippee=top_tippee, ) diff --git a/gratipay/models/participant.py b/gratipay/models/participant.py index 5550bcd3ef..0b658e0a3f 100644 --- a/gratipay/models/participant.py +++ b/gratipay/models/participant.py @@ -623,6 +623,7 @@ def remove_email(self, address): (self.username, address)) def send_email(self, spt_name, **context): + context['participant'] = self context['username'] = self.username context['button_style'] = ( "color: #fff; text-decoration:none; display:inline-block; " From 5973342ab05b198a55b49eda1f180e2c7512eb7e Mon Sep 17 00:00:00 2001 From: ChangacoDate: Thu, 9 Apr 2015 23:41:28 +0200 Subject: [PATCH 11/16] send notifications for successful charges by default --- sql/branch.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/branch.sql b/sql/branch.sql index 7bc2597432..577a220d79 100644 --- a/sql/branch.sql +++ b/sql/branch.sql @@ -1,5 +1,5 @@ BEGIN; - ALTER TABLE participants ADD COLUMN notify_charge int DEFAULT 1; + ALTER TABLE participants ADD COLUMN notify_charge int DEFAULT 3; ALTER TABLE participants ALTER COLUMN notify_on_opt_in DROP DEFAULT, ALTER COLUMN notify_on_opt_in TYPE int USING notify_on_opt_in::int, From a5c9f8f22f5da419cb671b2b28a775af00f53757 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Mon, 13 Apr 2015 17:56:02 -0400 Subject: [PATCH 12/16] Show total amount charged, including processor fee --- emails/charge_failed.spt | 4 ++-- emails/charge_succeeded.spt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emails/charge_failed.spt b/emails/charge_failed.spt index 519f384444..a542640077 100644 --- a/emails/charge_failed.spt +++ b/emails/charge_failed.spt @@ -5,7 +5,7 @@ "We tried to charge your credit card {0} today, to fund your weekly payment to {1}, but it failed.", "We tried to charge your credit card {0} today, to fund your weekly payments to {1}, but it failed.", ntippees, - format_currency(exchange.amount, 'USD'), + format_currency(exchange.amount + exchange.fee, 'USD'), top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) ) }} @@ -21,7 +21,7 @@ "We tried to charge your credit card {0} today, to fund your weekly payment to {1}, but it failed.", "We tried to charge your credit card {0} today, to fund your weekly payments to {1}, but it failed.", ntippees, - format_currency(exchange.amount, 'USD'), + format_currency(exchange.amount + exchange.fee, 'USD'), top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) ) }} diff --git a/emails/charge_succeeded.spt b/emails/charge_succeeded.spt index d05e26afbe..4cd59942ba 100644 --- a/emails/charge_succeeded.spt +++ b/emails/charge_succeeded.spt @@ -5,7 +5,7 @@ "We charged your credit card {0} today, to fund your weekly payment to {1}. Thanks for using Gratipay!", "We charged your credit card {0} today, to fund your weekly payments to {1}. Thanks for using Gratipay!", ntippees, - format_currency(exchange.amount, 'USD'), + format_currency(exchange.amount + exchange.fee, 'USD'), ('{1}'|safe).format( participant.profile_url+'giving/', top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) @@ -16,7 +16,7 @@ "We charged your credit card {0} today, to fund your weekly payment to {1}. Thanks for using Gratipay!", "We charged your credit card {0} today, to fund your weekly payments to {1}. Thanks for using Gratipay!", ntippees, - format_currency(exchange.amount, 'USD'), + format_currency(exchange.amount + exchange.fee, 'USD'), top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) ) }} From 3e39acd50a4b00dbcf0452cb3e8cdddd582f8546 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Mon, 13 Apr 2015 18:43:38 -0400 Subject: [PATCH 13/16] Tweak language of charge notifications --- emails/charge_failed.spt | 41 +++++++++++++++++-------------------- emails/charge_succeeded.spt | 30 +++++++++++++-------------- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/emails/charge_failed.spt b/emails/charge_failed.spt index a542640077..6686b4cfcd 100644 --- a/emails/charge_failed.spt +++ b/emails/charge_failed.spt @@ -1,31 +1,28 @@ -{{ ngettext("Your payment failed!", "Your payments failed!", ntippees) }} +{{ _("Oh no! A problem supporting {0}!", top_tippee) }} [---] text/html -{{ ngettext( - "We tried to charge your credit card {0} today, to fund your weekly payment to {1}, but it failed.", - "We tried to charge your credit card {0} today, to fund your weekly payments to {1}, but it failed.", - ntippees, - format_currency(exchange.amount + exchange.fee, 'USD'), - top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) - ) }} +{{ _("We tried to charge your credit card {0} today, to fund your ongoing support for {1}, but the charge failed with this message:", + format_currency(exchange.amount + exchange.fee, 'USD'), + ('{1}'|safe).format( + participant.profile_url+'giving/', + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', + '{0} and {n} others', + ntippees - 1, + top_tippee))) }} -{{ _("The error message we received from our payment processor is:") }} +- -{{ _("Fix your credit card") }} +{{ _("Fix your credit card?") }} [---] text/plain -{{ ngettext( - "We tried to charge your credit card {0} today, to fund your weekly payment to {1}, but it failed.", - "We tried to charge your credit card {0} today, to fund your weekly payments to {1}, but it failed.", - ntippees, - format_currency(exchange.amount + exchange.fee, 'USD'), - top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) - ) }} - -{{ _("The error message we received from our payment processor is:") }} +{{ _("We tried to charge your credit card {0} today, to fund your ongoing support for {1}, but the charge failed with this message:", + ntippees, + format_currency(exchange.amount + exchange.fee, 'USD'), + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', + '{0} and {n} others', + ntippees - 1, + top_tippee)) }} {{ exchange.note }} diff --git a/emails/charge_succeeded.spt b/emails/charge_succeeded.spt index 4cd59942ba..0ace696d6b 100644 --- a/emails/charge_succeeded.spt +++ b/emails/charge_succeeded.spt @@ -1,23 +1,21 @@ -{{ ngettext("Your payment succeeded!", "Your payments succeeded!", ntippees) }} +{{ _("Thanks for supporting {0}!", top_tippee) }} [---] text/html -{{ ngettext( - "We charged your credit card {0} today, to fund your weekly payment to {1}. Thanks for using Gratipay!", - "We charged your credit card {0} today, to fund your weekly payments to {1}. Thanks for using Gratipay!", - ntippees, - format_currency(exchange.amount + exchange.fee, 'USD'), - ('{1}'|safe).format( +{{ _("We charged your credit card {0} today, to fund your ongoing support for {1}. Thanks for using Gratipay!", + format_currency(exchange.amount + exchange.fee, 'USD'), + ('{1}'|safe).format( participant.profile_url+'giving/', - top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) - )) }} + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', + '{0} and {n} others', + ntippees - 1, + top_tippee))) }} [---] text/plain -{{ ngettext( - "We charged your credit card {0} today, to fund your weekly payment to {1}. Thanks for using Gratipay!", - "We charged your credit card {0} today, to fund your weekly payments to {1}. Thanks for using Gratipay!", - ntippees, - format_currency(exchange.amount + exchange.fee, 'USD'), - top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', ntippees - 1, top_tippee) - ) }} +{{ _("We charged your credit card {0} today, to fund your ongoing support for {1}. Thanks for using Gratipay!", + format_currency(exchange.amount + exchange.fee, 'USD'), + top_tippee if ntippees == 1 else ngettext('{0} and {n} other', + '{0} and {n} others', + ntippees - 1, + top_tippee)) }} {{ _("Follow this link if you want to view or modify your payments:") }} {{ participant.profile_url+'giving/' }} From f37d238ce5bebd64426e484b54822ca9da709e93 Mon Sep 17 00:00:00 2001 From: Chad Whitacre{{ exchange.note }}-{{ exchange.note }} -Date: Mon, 13 Apr 2015 19:48:01 -0400 Subject: [PATCH 14/16] Link to receipt for successful charges --- emails/charge_failed.spt | 2 +- emails/charge_succeeded.spt | 6 ++++++ gratipay/billing/payday.py | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/emails/charge_failed.spt b/emails/charge_failed.spt index 6686b4cfcd..b230499242 100644 --- a/emails/charge_failed.spt +++ b/emails/charge_failed.spt @@ -13,7 +13,7 @@ {{ exchange.note }}{{ _("Fix your credit card?") }} + style="{{ button_style }}">{{ _("Fix Credit Card") }} [---] text/plain {{ _("We tried to charge your credit card {0} today, to fund your ongoing support for {1}, but the charge failed with this message:", diff --git a/emails/charge_succeeded.spt b/emails/charge_succeeded.spt index 0ace696d6b..601b4df4cc 100644 --- a/emails/charge_succeeded.spt +++ b/emails/charge_succeeded.spt @@ -9,6 +9,10 @@ '{0} and {n} others', ntippees - 1, top_tippee))) }} +
+
+{{ _("View Receipt") }} [---] text/plain {{ _("We charged your credit card {0} today, to fund your ongoing support for {1}. Thanks for using Gratipay!", @@ -18,4 +22,6 @@ ntippees - 1, top_tippee)) }} +{{ _("Follow this link to view your receipt:") }} {{ '{}receipts/{}.html'.format(participant.profile_url, exchange.id) }} + {{ _("Follow this link if you want to view or modify your payments:") }} {{ participant.profile_url+'giving/' }} diff --git a/gratipay/billing/payday.py b/gratipay/billing/payday.py index 94dade64cf..07c8babe55 100644 --- a/gratipay/billing/payday.py +++ b/gratipay/billing/payday.py @@ -710,7 +710,7 @@ def end(self): def notify_participants(self): ts_start, ts_end = self.ts_start, self.ts_end exchanges = self.db.all(""" - SELECT amount, fee, note, status, p.*::participants AS participant + SELECT e.id, amount, fee, note, status, p.*::participants AS participant FROM exchanges e JOIN participants p ON e.participant = p.username WHERE "timestamp" >= %(ts_start)s @@ -751,7 +751,7 @@ def notify_participants(self): """, locals()) p.queue_email( 'charge_'+e.status, - exchange=dict(amount=e.amount, fee=e.fee, note=e.note), + exchange=dict(id=e.id, amount=e.amount, fee=e.fee, note=e.note), ntippees=ntippees, top_tippee=top_tippee, ) From cd7f418e4ab92ed35923b22436345fbb8e355cd8 Mon Sep 17 00:00:00 2001 From: ChangacoDate: Wed, 15 Apr 2015 10:25:54 +0200 Subject: [PATCH 15/16] fix text page of `charge_failed.spt` --- emails/charge_failed.spt | 1 - 1 file changed, 1 deletion(-) diff --git a/emails/charge_failed.spt b/emails/charge_failed.spt index b230499242..192ce2c51c 100644 --- a/emails/charge_failed.spt +++ b/emails/charge_failed.spt @@ -17,7 +17,6 @@ [---] text/plain {{ _("We tried to charge your credit card {0} today, to fund your ongoing support for {1}, but the charge failed with this message:", - ntippees, format_currency(exchange.amount + exchange.fee, 'USD'), top_tippee if ntippees == 1 else ngettext('{0} and {n} other', '{0} and {n} others', From c67335addec6a9742fdd9168b0e56c124fc26287 Mon Sep 17 00:00:00 2001 From: Changaco Date: Wed, 15 Apr 2015 10:34:34 +0200 Subject: [PATCH 16/16] fix `record_exchange`: store the `error` in `note` --- gratipay/billing/exchanges.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gratipay/billing/exchanges.py b/gratipay/billing/exchanges.py index 482fb24450..35775631e0 100644 --- a/gratipay/billing/exchanges.py +++ b/gratipay/billing/exchanges.py @@ -266,7 +266,7 @@ def _prep_hit(unrounded): return cents, amount_str, upcharged, fee -def record_exchange(db, route, amount, fee, participant, status, error=''): +def record_exchange(db, route, amount, fee, participant, status, error=None): """Given a Bunch of Stuff, return an int (exchange_id). Records in the exchanges table have these characteristics: @@ -284,10 +284,10 @@ def record_exchange(db, route, amount, fee, participant, status, error=''): exchange_id = cursor.one(""" INSERT INTO exchanges - (amount, fee, participant, status, route) - VALUES (%s, %s, %s, %s, %s) + (amount, fee, participant, status, route, note) + VALUES (%s, %s, %s, %s, %s, %s) RETURNING id - """, (amount, fee, participant.username, status, route.id)) + """, (amount, fee, participant.username, status, route.id, error)) if status == 'failed': propagate_exchange(cursor, participant, route, error, 0)