From 5711c8b99a8b43704790fa4612755bad5549383c Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 30 Apr 2019 20:27:52 +0200 Subject: [PATCH 1/2] Set script_location in alembic.ini --- migrations/alembic.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/migrations/alembic.ini b/migrations/alembic.ini index f8ed480..ba209c6 100644 --- a/migrations/alembic.ini +++ b/migrations/alembic.ini @@ -8,6 +8,7 @@ # the 'revision' command, regardless of autogenerate # revision_environment = false +script_location = . # Logging configuration [loggers] From a91d676cce462814203cdf2f1be26c65d1f5b8ca Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Mon, 6 May 2019 17:59:05 +0200 Subject: [PATCH 2/2] Add currency to support_level --- app/api/routes.py | 6 ++--- app/main/routes.py | 14 ++++++++++- app/models.py | 8 +++---- app/tasks.py | 2 +- app/templates/admin/custom_list.html | 3 ++- app/templates/main/creditcard.html | 5 ++-- app/templates/main/support.html | 6 ++--- ...13ea9c15280_add_currency_to_price_level.py | 23 +++++++++++++++++++ requirements.txt | 1 + tests/conftest.py | 3 +++ 10 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 migrations/versions/c13ea9c15280_add_currency_to_price_level.py diff --git a/app/api/routes.py b/app/api/routes.py index 9b3f101..e990e11 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -84,9 +84,9 @@ def update_sub(): return "Invalid transaction ID.", 400 -@bp.route('/v1/square/', methods=['GET', 'POST']) +@bp.route('/v1/square//', methods=['GET', 'POST']) @login_required -def process_square(price): +def process_square(price, currency): ''' Receives a nonce from Square, and uses the nonce to charge the card. Upon successful charge, it updates the @@ -147,7 +147,7 @@ def process_square(price): transactions_api = TransactionsApi(api_client) idempotency_key = str(uuid.uuid1()) cents = price * 100 - amount = {'amount': cents, 'currency': 'USD'} + amount = {'amount': cents, 'currency': currency} body = { 'idempotency_key': idempotency_key, 'customer_id': current_user.square_id, diff --git a/app/main/routes.py b/app/main/routes.py index 93c1f8b..851a6bd 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -1,6 +1,7 @@ from app import blog_engine, db from app.main import bp from app.models import BTCPayClientStore, Square, PriceLevel +from babel import numbers from datetime import datetime from flask import redirect, url_for, flash, render_template, request,\ current_app @@ -87,16 +88,19 @@ def support(): name='Patron', description="You're a patron!", price=10, + currency='USD' ) level_2 = PriceLevel( name='Cooler Patron', description="You're a cooler patron!", price=20, + currency='USD' ) level_3 = PriceLevel( name='Coolest Patron', description="You're the best!", price=60, + currency='USD' ) db.session.add(level_1) db.session.add(level_2) @@ -109,6 +113,7 @@ def support(): 'main/support.html', levels=price_levels, square=square, + numbers=numbers ) @@ -117,6 +122,7 @@ def support(): def credit_card(): # directs user to sqpaymentform.js price = request.args.get('price') + currency = request.args.get('currency') or 'USD' if price is None: flash('There was an error. Try again.') return redirect(url_for('main.support')) @@ -127,6 +133,8 @@ def credit_card(): application_id=square.application_id, location_id=square.location_id, price=price, + currency=currency, + numbers=numbers ) else: return redirect(url_for('main.index')) @@ -152,6 +160,7 @@ def create_invoice(): else: plan = price_level.name price = price_level.price + currency = price_level.currency or 'USD' else: return redirect(url_for('main.support')) else: @@ -160,6 +169,9 @@ def create_invoice(): return redirect(url_for('main.support')) plan = request.args.get('name') price = int(string_price) + currency = request.args.get('currency') + if currency is None: + currency = 'USD' compare = PriceLevel.query.filter_by(price=price).first() if compare is None: return redirect(url_for('main.support')) @@ -183,7 +195,7 @@ def create_invoice(): try: inv_data = btc_client.create_invoice({ "price": price, - "currency": "USD", + "currency": currency, "buyer": { "name": current_user.username, "email": current_user.email, diff --git a/app/models.py b/app/models.py index 6a5d537..28bacf3 100644 --- a/app/models.py +++ b/app/models.py @@ -52,7 +52,7 @@ class PriceLevel(db.Model): name = db.Column(db.String(64), index=True, unique=True) price = db.Column(db.Integer, index=True, unique=True) description = db.Column(db.Text) - + currency = db.Column(db.String(3)) class BTCPayClientStore(db.Model): # object for storing pickled BTCPay API client @@ -100,9 +100,9 @@ def __str__(self): expire_date = self.expiration.date() return f''' {self.id}, - {self.username}, - {self.email}, - {expire_date}, + {self.username}, + {self.email}, + {expire_date}, {self.role}, {self.mail_opt_out} ''' diff --git a/app/tasks.py b/app/tasks.py index 9fe483c..3e49570 100644 --- a/app/tasks.py +++ b/app/tasks.py @@ -80,7 +80,7 @@ def renewals_square(begin): failed_list.append(user) continue cents = price_level.price * 100 - amount = {'amount': cents, 'currency': 'USD'} + amount = {'amount': cents, 'currency': price_level.currency or 'USD'} body = { 'idempotency_key': idempotency_key, 'customer_id': user.square_id, diff --git a/app/templates/admin/custom_list.html b/app/templates/admin/custom_list.html index 05c80a8..014deae 100644 --- a/app/templates/admin/custom_list.html +++ b/app/templates/admin/custom_list.html @@ -6,7 +6,8 @@

Pricing Setup

Notes if Square Recurring Billing is Active:

    -
  1. Deleting a price level will deactivate recurring credit card billing for all users that that price level. On their renewal date, they'll get an email with a link to choose a new plan.
  2. +
  3. The currency must match your Square home currency
  4. +
  5. Deleting a price level will deactivate recurring credit card billing for all users that that price level. On their renewal date, they'll get an email with a link to choose a new plan.
  6. Changing the name of a price level will also deactivate recurring credit card billing for all users that that price level. On their renewal date, they'll get an email with a link to choose a new plan.
  7. Changing the price of a given plan will not alter recurring billing so long as the plan keeps the same name. Your users will be billed the new price, so to not blindside your users it is suggested that you post an update with your new pricing and set said update to be emailed.
  8. Changing the description of a price level has no effects on recurring billing.
  9. diff --git a/app/templates/main/creditcard.html b/app/templates/main/creditcard.html index 3206676..3f234b6 100644 --- a/app/templates/main/creditcard.html +++ b/app/templates/main/creditcard.html @@ -28,7 +28,7 @@ the Transaction API charge endpoint URL you want to POST the nonce to (for example, "/process-card") --> -
    +
    Card Number
    @@ -49,7 +49,7 @@
- +
@@ -64,4 +64,3 @@ {% endblock main %} {% block extrajs %} {% endblock extrajs %} - diff --git a/app/templates/main/support.html b/app/templates/main/support.html index 09a4f4c..2df94b6 100644 --- a/app/templates/main/support.html +++ b/app/templates/main/support.html @@ -12,11 +12,11 @@

Support Levels

{{ level.name }}

-

${{ level.price }} / mo

+

{{ numbers.format_currency(level.price, level.currency, locale='en') }} / mo

{{ level.description }}

-

Subscribe (Bitcoin)

+

Subscribe (Bitcoin)

{%if square %} -

Subscribe (Fiat)

+

Subscribe (Fiat)

{% endif %}
diff --git a/migrations/versions/c13ea9c15280_add_currency_to_price_level.py b/migrations/versions/c13ea9c15280_add_currency_to_price_level.py new file mode 100644 index 0000000..5e7cca9 --- /dev/null +++ b/migrations/versions/c13ea9c15280_add_currency_to_price_level.py @@ -0,0 +1,23 @@ +"""Add currency to price level + +Revision ID: c13ea9c15280 +Revises: 5346190a2f75 +Create Date: 2019-04-30 20:08:08.487672 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c13ea9c15280' +down_revision = '5346190a2f75' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('price_level', sa.Column('currency', sa.String(length=3), default="USD")) + +def downgrade(): + op.drop_column('price_level', 'currency') diff --git a/requirements.txt b/requirements.txt index 67e87b3..56d79a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ alembic==1.0.5 APScheduler==3.5.3 asn1crypto==0.24.0 +Babel==2.6.0 blinker==1.4 btcpay-python==1.1.0 certifi==2018.11.29 diff --git a/tests/conftest.py b/tests/conftest.py index 45f5ee3..8cff908 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -52,16 +52,19 @@ def init_database(new_user, test_mail): level_1 = PriceLevel( name='Patron', description="You're a patron!", + currency="USD", price=10, ) level_2 = PriceLevel( name='Cooler Patron', description="You're a cooler patron!", + currency="USD", price=20, ) level_3 = PriceLevel( name='Coolest Patron', description="You're the best!", + currency="USD", price=60, ) db.session.add(level_1)