From 4e452515630a6c3017ccaa23e0f8281b49ff76d6 Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Wed, 16 Nov 2016 22:58:46 +0000 Subject: [PATCH] Work on payment system --- Dockerfile | 5 +- docker-compose.yml | 3 + requirements.txt | 9 +- tests/test_payment_gateways.py | 4 + website/libs/payments.py | 135 ++++++++--------------- website/pages/profile.py | 46 ++++++-- website/static/css/default.css | 2 +- website/tools/list_registered_members.py | 29 ++++- website/widgets/member_card.py | 2 +- 9 files changed, 126 insertions(+), 109 deletions(-) diff --git a/Dockerfile b/Dockerfile index f129af7..b54ef36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,11 +7,12 @@ ENV SITE_FOLDER /etc/sites/mysite/ #COPY website/config/uwsgi/maidstone-hackspace.org.uk.ini /etc/sites/uwsgi/maidstone-hackspace.org.uk.ini RUN apk add --update --no-cache libssl1.0 libxml2 libxslt ca-certificates -RUN apk add --update --no-cache py-psycopg2 py-lxml py-flask py-pillow py-openssl py-cffi +RUN apk add --update --no-cache py-psycopg2 py-lxml py-pillow py-openssl py-cffi RUN apk add --update --no-cache build-base make git bzr python3-dev libffi-dev openssl-dev libxml2-dev libxslt-dev jpeg-dev zlib-dev && \ pip3 install lxml && \ - pip3 install --no-cache-dir lxml dateutils requests requests-oauthlib mailer gocardless paypalrestsdk pytz pytest nose2 oauthlib flask flask-login pymysql misaka slimit cssmin pillow && \ + pip3 install -r requirements.txt && \ + pip3 install --no-cache-dir lxml dateutils requests requests-oauthlib mailer gocardless paypalrestsdk pytz pytest nose2 oauthlib pymysql misaka slimit cssmin pillow && \ #pip3 install --upgrade git+git://github.com/olymk2/scaffold.git@master && \ pip3 install --upgrade --no-cache-dir bzr+lp:scaffold/trunk#egg=scaffold && \ apk del build-base make git bzr python3-dev libffi-dev openssl-dev libxml2-dev libxslt-dev diff --git a/docker-compose.yml b/docker-compose.yml index a34836e..bea79be 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,7 +21,10 @@ services: container_name: mhackspace_web image: olymk2/nginx restart: unless-stopped + network_mode: bridge + ports: + - 80:80 dns: - 8.8.8.8 - 8.8.4.4 diff --git a/requirements.txt b/requirements.txt index 01be8a8..adf8f7d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,14 @@ flask +flask-login==0.3.2 lxml requests pytz -pip install -e bzr+lp:scaffold#egg=scaffold -python-requests-oauthlib +bzr+lp:scaffold#egg=scaffold +requests_oauthlib +#python-requests-oauthlib paypalrestsdk -dateutil +python-dateutil +#dateutil gocardless_pro braintree diff --git a/tests/test_payment_gateways.py b/tests/test_payment_gateways.py index a5fcef8..818b030 100644 --- a/tests/test_payment_gateways.py +++ b/tests/test_payment_gateways.py @@ -25,6 +25,10 @@ class TestPaymentGatewaysGocardless(unittest.TestCase): self.provider = gocardless_provider() return self.provider #self.provider + def test_confirm_subscription_callback(self): + with patch('gocardless.client.confirm_resources') as mock_subscription: + self.provider = gocardless_provider() + def test_fetch_subscription_gocardless(self): items = [Mock( id='01', diff --git a/website/libs/payments.py b/website/libs/payments.py index 5faff23..58380f0 100644 --- a/website/libs/payments.py +++ b/website/libs/payments.py @@ -8,6 +8,8 @@ import paypalrestsdk as paypal from website.config import settings from website.config.settings import app_domain +from website.config.logger import log + PROVIDER_ID = {'gocardless':1, 'paypal': 2} PROVIDER_NAME = {1: 'gocardless', 2: 'paypal'} @@ -15,86 +17,13 @@ PROVIDER_NAME = {1: 'gocardless', 2: 'paypal'} def select_provider(type): if type == "gocardless": return gocardless_provider() if type == "braintree": return braintree_provider() - if type == "paypal": return paypal_provider() + if type == "paypal": return paypal_provider() + + log.exception('[scaffold] - "No Provider for ' + type) assert 0, "No Provider for " + type -class paypal_provider: - def __init__(self): - print(settings.payment_providers['paypal']['credentials']) - print(paypal.configure(**settings.payment_providers['paypal']['credentials'])) - - def fetch_subscriptions(self): - #~ I-S39170DK26AF - start_date, end_date = "2014-07-01", "2016-07-20" - # plans_created = paypal.BillingPlan.all({"status": "CREATED", "sort_order": "DESC"}) - - # billing_agreement = paypal.BillingAgreement.all() - # billing_agreement = paypal.BillingAgreement.find('0HX53832PF841861G') - # print(billing_agreement) - # print(dir(billing_agreement)) - # print billing_agreement.search_transactions(start_date, end_date) - #~ transactions = billing_agreement.search_transactions(start_date, end_date) - # payment_history = paypal.Payment.all({"count":transactions 2}) - - # List Payments - # print("List Payment:") - # print(payment_history) - # for payment in payment_history.payments: - # print(" -> Payment[%s]" % (payment.id)) - #~ print paypal.BillingAgreement.all() - history = paypal.Invoice.all({"page_size": 2}) - - print("List Invoice:") - for invoice in history.invoices: - print(" -> Invoice[%s]" % (invoice.id)) - print(invoice.to_dict()) - - payment_history = paypal.Payment.all({"count": 10}) - print('List payments') - print(dir(payment_history)) - for payment in payment_history.payments: - print(payment['id']) - # print(payment['payer']['payer_info']['name']) - # print(payment['payer']['payer_info']['email']) - # print(pprint(payment['transactions'])) - for transact in payment['transactions']: - print(transact['amount']['total']) - # print(payment_history.payments) - - - history = paypal.BillingPlan.all( - {"status": "CREATED", "page_size": 5, "page": 1, "total_required": "yes"}) - # print(history) - - print("List BillingPlan:") - for plan in history.plans: - print(plan['id']) - - billing_agreement = paypal.BillingAgreement.find(plan['id']) - print('agreement') - print(billing_agreement.search_transactions(start_date, end_date)) - print(billing_agreement.to_dict()) - print(dir(plan)) - print(plan.to_dict()) - print(plan['name']) - print(" -> BillingPlan[%s]" % (plan.id)) - - yield { - 'status': paying_member.status, - 'email': user.email, - 'start_date': paying_member.created_at, - 'reference': paying_member.id, - 'amount': paying_member.amount} - #~ merchant = gocardless.client.merchant() - #~ for paying_member in merchant.subscriptions(): - #~ user=paying_member.user() - #~ yield { - #~ 'email': user.email, - #~ 'start_date': paying_member.created_at, - #~ 'reference': paying_member.id, - #~ 'amount': paying_member.amount} - class gocardless_provider: + form_remote = True client = None def __init__(self): @@ -107,7 +36,16 @@ class gocardless_provider: gocardless.environment = settings.payment_providers['gocardless']['environment'] gocardless.set_details(**settings.payment_providers['gocardless']['credentials']) self.client = gocardless.client.merchant() - + + def subscribe_confirm(self, args): + response = gocardless.client.confirm_resource(args) + subscription = gocardless.client.subscription(args.get('resource_id')) + return { + 'amount': subscription.amount, + 'start_date': subscription.created_at, + 'reference': subscription.id + } + def fetch_subscriptions(self): for paying_member in self.client.subscriptions(): user=paying_member.user() @@ -115,24 +53,33 @@ class gocardless_provider: # print('test') # print(dir(bill)) # print(bill.created_at) + print(dir(paying_member)) + print(paying_member.reference_fields) yield { 'status': paying_member.status, 'email': user.email, 'start_date': paying_member.created_at, - 'reference': paying_member.reference, + 'reference': paying_member.id, 'amount': paying_member.amount} + def get_redirect_url(self): + return settings.payment_providers['gocardless']['redirect_url'] + + def get_token(self): + return 'N/A' + def create_subscription(self, amount, name, redirect_success, redirect_failure, interval_unit='month', interval_length='1'): - if self.provider == 'gocardless': - return gocardless.client.new_subscription_url( - amount=float(amount), - interval_length=interval_length, - interval_unit=interval_unit, - name=name, - redirect_uri=redirect_success) + return gocardless.client.new_subscription_url( + amount=float(amount), + interval_length=interval_length, + interval_unit=interval_unit, + name=name, + redirect_uri=redirect_success) class braintree_provider: + form_remote = False + def __init__(self): braintree.Configuration.configure( environment=braintree.Environment.Sandbox, @@ -140,13 +87,23 @@ class braintree_provider: public_key=settings.payment_providers['braintree']['credentials']['public_key'], private_key=settings.payment_providers['braintree']['credentials']['private_key']) + def get_token(self): + return braintree.ClientToken.generate() + def create_subscription(self, amount, name, redirect_success, redirect_failure, interval_unit='month', interval_length='1'): - braintree.Subscription.create({ + result = braintree.Customer.create({ + "first_name": "test", + "last_name": "user", + "payment_method_nonce": nonce_from_the_client + }) + + return braintree.Subscription.create({ "payment_method_token": "the_token", "plan_id": "membership", - "price": 20.00, - + "merchant_account_id": "gbp_sandbox" + #"price": "20.00" + #'name': name }) def fetch_subscriptions(self): diff --git a/website/pages/profile.py b/website/pages/profile.py index 07748f9..0d85548 100644 --- a/website/pages/profile.py +++ b/website/pages/profile.py @@ -14,7 +14,7 @@ from website.data import badges from website.data import members from website.config.settings import app_domain -from website.libs.payments import payment +from website.libs.payments import payment, select_provider from website.config.settings import * profile_pages = Blueprint('profile_pages', __name__, template_folder='templates') @@ -81,8 +81,7 @@ def index(): ).render() ).set_classes('col s6').render() ) - - + web.template.body.append(web.page.render()) web.template.body.append(web.popup.create('').render()) @@ -101,7 +100,8 @@ def setup(): for member in fetch_users(): user_lookup[member.get('email')] = member.get('user_id') - provider = payment(provider='paypal', style='payment') + provider = select_provider('braintree') + # provider = payment(provider='paypal', style='payment') for item in provider.fetch_subscriptions(): print(item) @@ -112,7 +112,7 @@ def setup(): print(paying_member.user()) print(paying_member.amount) user=paying_member.user() - + print(user.email) user_id = user_lookup.get(user.email) print(user_id) @@ -122,17 +122,37 @@ def setup(): return footer() + + +@profile_pages.route("/profile/membership/form", methods=['get']) +@login_required +def pay_membership_form(): + selected_provider = request.form.get('provider', 'braintree') + provider = select_provider(type=selected_provider) + + web.template.create('Maidstone Hackspace') + header('Maidstone Hackspace Member registration') + + web.form_braintree.create(client_token=provider.get_token()) + web.page.section(web.form_braintree.render()) + web.template.body.append(web.page.render()) + return footer() + + @profile_pages.route("/profile/membership", methods=['POST']) @login_required def pay_membership(): + selected_provider = request.form.get('provider', 'gocardless') + provider = select_provider(type=selected_provider) + if provider.form_remote is False: + return redirect('/profile/membership/form') user = get_user_details({'id': current_user.get_id()}).get() user_code = str(user.get('user_id')).zfill(5) - selected_provider = request.form.get('provider', 'gocardless') - provider = payment(provider=selected_provider, style='payment') - success_url = '%s/profile/membership/%s/success' % (app_domain, selected_provider) - failure_url = '%s/profile/membership/%s/failure' % (app_domain, selected_provider) - url = provider.subscribe( + # provider = payment(provider=selected_provider, style='payment') + success_url = '%s/profile/membership/%s/success' % (provider.get_redirect_url(), selected_provider) + failure_url = '%s/profile/membership/%s/failure' % (provider.get_redirect_url(), selected_provider) + url = provider.create_subscription( amount=request.form.get('amount'), name="Membership your membership id is MH%s" % user_code, redirect_success=success_url, @@ -155,7 +175,8 @@ def cancel_membership(): print(subscription.get('subscription_reference')) - provider = payment(provider='paypal', style='payment') + provider = select_provider(type='braintree') + # provider = payment(provider='paypal', style='payment') provider.lookup_provider_by_id(1) url = provider.unsubscribe(reference=subscription.get('subscription_reference')) @@ -170,7 +191,8 @@ def membership_signup(provider): web.template.create('Maidstone Hackspace') header('Maidstone Hackspace Member registration') - provider = payment(provider=provider, style='payment') + provider = select_provider(type=provider) + # provider = payment(provider=provider, style='payment') payment_details = provider.subscribe_confirm(request.args) try: diff --git a/website/static/css/default.css b/website/static/css/default.css index b0d8fc1..839ca16 100644 --- a/website/static/css/default.css +++ b/website/static/css/default.css @@ -1 +1 @@ -.dark-blue{background-color:#00232D;color:#fff}.blue{background-color:#0087A8}.content{margin:20px}html{background-color:#fff;height:100%;font-family:'Arial';font-size:18px}body{margin:0;padding:0}a{color:#fff}li p{margin:20px 0 0 30px;height:45px}fieldset{margin:20px}textarea{background-color:#fff!important}textarea.materialize-textarea{background-color:#fff;padding:10px}.select-wrapper input.select-dropdown{background-color:#fff;color:#000;padding-left:10px}input:not([type]),input[type=text],input[type=password],input[type=email],input[type=url],input[type=time],input[type=date],input[type=datetime],input[type=datetime-local],input[type=tel],input[type=number],input[type=search],textarea.materialize-textarea{background-color:#fff;padding-left:10px}label{color:#fff;padding-left:20px}label.active{-webkit-transform:translateY(-180%)!important;transform:translateY(-180%)!important;color:#fff!important}.select-wrapper+label{top:-24px;color:#fff}select{margin:0;color:#000;padding:10px}p{margin-bottom:25px;margin-right:25px;line-height:150%}h1{color:#fff}h2{color:#fff}h3{color:#fff;font-size:20px}li{padding-bottom:10px;line-height:150%}.left{float:left}.right{float:right}.hide{display:none}#ajaxPopup{position:absolute;width:750px;height:550px;background-color:#fff;top:68px;left:50%;margin-left:-375px;box-shadow:0 1px 2px 0 rgba(0,0,0,0.2);background-color:#93B1C6}#ajaxPopup legend{width:720px;padding:15px;color:#fff;background-color:#000;margin:0}#ajaxPopup fieldset{border:0;margin:0;padding:0}#ajaxPopup label{width:160px;color:#000;line-height:48px}#ajaxPopup p{margin:20px}#ajaxPopup input{width:50%}#ajaxPopup button{position:absolute;bottom:0}#ajaxPopup .bottom{position:absolute;bottom:0}#ajaxPopup .full_width{left:0;right:0}.margin_default{margin:10px}.header span{font-size:100px}.headerbar{background-color:#E7EAEF}.footer{width:100%:margin:auto;height:40px;background-color:#ddd;border-top:1px solid #aaa;border-bottom:1px solid #aaa}.footerbar{background-color:#E7EAEF;border-top:1px solid #D2D2D2;border-bottom:1px solid #D2D2D2;margin-top:60px}.pageFooter{clear:both}.pageHeader{padding:20px;color:#fff;font-size:24px}.pagination{height:40px;font-size:16px}.pagination li.active{background-color:#0a2024}.pagination li{float:left;list-style-type:none;margin-left:12px;background-color:#7eabb8;padding:2px;border:2px solid #000;border-radius:6px}.pagination li:hover{background-color:#0a2128}.pagination li a{text-decoration:none;color:#000}.on{background-color:#1e424c!important}.clear{clear:both}table{width:100%;background-color:#eee;font-size:11px;border-collapse:collapse;border-spacing:0;box-shadow:0 1px 3px 0 rgba(0,0,0,0.12),0px 1px 2px 0 rgba(0,0,0,0.24)}table tr{transition:all .3s ease 0s}table th{padding:16px}table td{padding:16px;border-bottom:1px solid rgba(0,0,0,0.12)}table caption{font-size:16px}tbody tr:nth-child(odd){background-color:#eee;font-size:11px}.tabrow1(background-color:#eee;) #topbar{position:relative;position:absolute;top:0;width:100%;z-index:10}.hover:hover{background-color:#9fa8da}.hover:hover{background-color:#9fa8da}.hover-expand:hover .children{display:block}.copyright{float:right;margin-top:20px;color:#fff}.tile-right{margin-top:20px;width:230px;float:right;margin-right:20px}.tile-right img{float:right}.tile-image{float:right;clear:right}#headerstrip{overflow:hidden;line-height:1px;position:absolute;left:0;right:0;height:68px;top:0;background-color:#00232D}#headerstrip .navstrip{box-shadow:none;margin:10px;height:48px;background-color:#00232D}#headerstrip .navstripleft{padding:0}#headerstrip .mini-logo-text{line-height:25px;position:absolute;left:56px;padding-top:12px;font-size:22px;color:#fff;font-weight:bold;padding-left:10px}#headerstrip .mini_logo{position:absolute;width:48px;height:48px}#headerstrip .mini-logo:hover{transition:ease-in-out;-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;-o-transform-origin:50% 50%;transform-origin:50% 50%;height:48px;width:48px;-webkit-animation:spin 2s linear infinite;-moz-animation:spin 2s linear infinite;animation:spin 2s linear infinite}#headerstrip .middle{}#menubar{margin-top:108px}#menubar nav{height:48px;background-color:#0087A8}#menubar nav ul{width:100%;height:100%}#menubar nav li{margin:10px}@-moz-keyframes spin{100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{100%{-webkit-transform:rotate(360deg)}}@keyframes spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.menu{position:absolute;left:0;right:0;height:408px;top:68px;background-color:#00232D;z-index:-1}.menu ul{width:960px;margin:auto;height:40px;padding-left:20px;background-color:#0087A8}.menu li{width:130px;float:left;list-style-type:none;margin-top:10px;padding:00px;text-align:center}.menu li:hover{width:130px;float:left;list-style-type:none;border-bottom:4px solid #1C4085}.menu a{color:#fff;font-weight:bold;text-decoration:none}.menu li:hover{}.page{margin:auto;margin-top:28px;padding-bottom:48px;background-color:#0087A8}.page .pageSection{margin-left:20px}.page .messages{color:#fff;border:10px solid #0087A8;background-color:#00232D;font-weight:bold}.page .messages li{padding:10px}.columns{float:right;clear:right;width:460px;margin-left:20px;margin-bottom:20px}.google-groups-signup{width:300px;float:left}.google-groups-signup input{margin-top:20px;width:290px;padding-left:10px}.google-groups-signup a{color:#fff;width:282px}.banner-slide{position:absolute;width:700px;margin:20px 20px 20px 0}.banner-slide ul{position:relative;overflow:hidden;width:700px;height:300px;margin:0}.banner-slide li{position:absolute;left:0;top:0;list-style-type:none;padding:0;margin:0}.banner-slide .button{background-color:#0087A8;border-radius:50%;opacity:.4}.banner-slide .content{color:#111;position:absolute;top:250px;width:100%;background-color:#eee;opacity:.4}.banner-slide .left{text-align:left;padding:6px;font-size:48px;color:#fff;position:absolute;top:122px;left:0;width:60px;height:60px;background-color:transparent}.banner-slide .right{text-align:right;padding:6px;font-size:48px;color:#fff;position:absolute;top:122px;right:15px;width:60px;height:60px;background-color:transparent}.slide-button{background-image:url('static/images/css/sprite-navigation-white.png')}.slide{position:absolute;left:0}.slide.ng-hide-add{left:0;opacity:1}.slide.ng-hide-add-active{transition:.9s linear all;opacity:0}.slide.ng-hide-remove{left:0;opacity:0}.slide.ng-hide-remove-active{transition:.9s linear all;opacity:1}.slide.ng-leave.ng-leave-active,.slide.ng-enter{transition:.5s linear all;left:0;opacity:0}.slide.ng-leave,.slide.ng-enter.ng-enter-active{transition:.5s linear all;left:0;opacity:1}.bullet-list li{margin:0;margin-left:10px;line-height:100%}.tile{position:relative;margin:0}.tile-border{background-color:#eee;margin-right:20px;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26)}.tile-img{height:200px;overflow:hidden;background-repeat:no-repeat;background-position:center;background-image:url('/static/images/background.png')}.tile header{background-color:#00232D;width:100%;bottom:20px;top:220px;overflow:auto;left:20px;right:20px;text-align:left;line-height:150%;font-size:12px}.tile h2{margin-left:25px;line-height:150%;font-size:12px;margin-right:20px}.tile p{margin-left:25px}.tile header a{color:#fff}.tile .content{overflow:hidden;bottom:20px;top:220px;overflow:auto;left:20px;right:20px;text-align:justify;line-height:20px;height:106px;font-size:12px}#footertop{background-color:#00232D;height:48px}#footerbottom{background-color:#0087A8;height:300px}#footerbottom div.container{margin:auto;background-color:#0087A8;height:250px;width:960px}.twitter-feed{width:460px;margin:20px}.social-chat{width:100%;height:480px;position:relative}.social-chat .contain{left:0;right:0;height:480px;position:absolue;margin:20px}.social-chat iframe{display:block;border:0;width:100%;height:100%}.social{z-index:1;position:absolute;right:0;top:0;margin-top:0}.social .socbtn{line-height:0;float:left;margin-left:20px;margin-top:20px}#login_box{width:500px;margin:auto;position:relative}#login_box p{color:#fff;padding:0;margin:0}#login_box label{display:block;margin:20px 0 20px}#login_box input{margin:20px 0 0;float:none;width:100%}#login_box button{margin:20px 0 0;float:left;width:100%}#login_box .providers{margin:20px 0 20px;height:48px;height:35px}#login_box .providers a{float:left;margin-right:30px}.members .stats{}.members .tile{width:220px;float:left}.members .tile-img{margin:auto;width:200px}.members .badge{width:32px;height:32px;margin:0;margin-top:5px}#member_navigation{z-index:2;position:fixed;top:68px;left:0;width:180px;height:100%}#member_navigation a{color:#fff;font-weight:bold;text-decoration:none}#member_navigation ul{padding:0;margin:0;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26)}#member_navigation li{margin:0;padding:10px;background-color:#0087A8;list-style-type:none}#member_navigation li:hover{background-color:#E7EAEF}.action-bar{overflow:hidden;position:fixed;right:50px;bottom:50px;width:65px;height:70px}.action-bar:hover{height:260px}.action-bar .container{position:absolute;left:0;bottom:0;width:62px;min-width:62px;max-width:62px;padding-bottom:5px}.action-bar-small{overflow:hidden;position:absolute;right:0;top:40px;width:32px;height:32px}.action-bar .action-bar-button{margin-top:20px}.action-bar-button{display:block;padding:19px;background-color:#FF2670;border-radius:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26);z-index:5}.action-bar-button-small{display:block;padding:19px;background-color:#FF2670;border-radius:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26);z-index:5}.closePopup{position:absolute;top:12px;right:12px;background-color:#FF2670;border-radius:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26);z-index:5}#membercard{color:#000;background-color:#8C50A5;border-radius:14px;box-shadow:0 2px 5px 0 rgba(0,0,0,0.5);background-image:url('/static/images/membership_card_background.png');width:430px;height:240px;margin-left:20px;text-shadow:1px 1px #FFF;position:relative;float:right}#membercard label{color:#000}#membercard label.active{color:#000!important}#membercard .row{margin-bottom:0}#membercard .input-field{margin:0}#membercard .date{position:absolute;margin:25px;top:0;left:0}#membercard p{margin:0}#membercard .container{position:relative;top:50%;width:100%}#membercard .middle{color:#000;position:absolute;top:-38px;width:100%;text-align:center;font-size:28px}#membercard legend{margin:0;font-weight:strong;height:40px}#membercard fieldset{position:absolute;top:0;left:0;right:0;padding:0;margin:6px;border:0;height:240px}.calendar{width:230px;height:300px;overflow:auto}.calendar ul{list-style:none;padding:0;margin:0}.calendar li{font-size:14px;padding:6px}.calendar li:first-child{color:#fff;background-color:#00232D}.calendar .but{width:80px;text-align:center}.but{border:1px solid #000a0d;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;font-size:12px;font-family:arial,helvetica,sans-serif;padding:10px 10px 10px 10px;text-decoration:none;display:inline-block;text-shadow:-1px -1px 0 rgba(0,0,0,0.3);font-weight:bold;color:#FFF;background-color:#003645;background-image:-webkit-gradient(linear,left top,left bottom,from(#003645),to(#00232D));background-image:-webkit-linear-gradient(top,#003645,#00232D);background-image:-moz-linear-gradient(top,#003645,#00232D);background-image:-ms-linear-gradient(top,#003645,#00232D);background-image:-o-linear-gradient(top,#003645,#00232D)} \ No newline at end of file +.dark-blue{background-color:#00232D;color:#fff}.blue{background-color:#0087A8}.content{margin:20px}html{background-color:#fff;height:100%;font-family:'Arial';font-size:18px}body{margin:0;padding:0}a{color:#fff}li p{margin:20px 0 0 30px;height:45px}fieldset{margin:20px}textarea{background-color:#fff!important}textarea.materialize-textarea{background-color:#fff;padding:10px}.select-wrapper input.select-dropdown{background-color:#fff;color:#000;padding-left:10px}input:not([type]),input[type=text],input[type=password],input[type=email],input[type=url],input[type=time],input[type=date],input[type=datetime],input[type=datetime-local],input[type=tel],input[type=number],input[type=search],textarea.materialize-textarea{background-color:#fff;padding-left:10px}label{color:#fff;padding-left:20px}label.active{-webkit-transform:translateY(-180%)!important;transform:translateY(-180%)!important;color:#fff!important}.select-wrapper+label{top:-24px;color:#fff}select{margin:0;color:#000;padding:10px}p{margin-bottom:25px;margin-right:25px;line-height:150%}h1{color:#fff}h2{color:#fff}h3{color:#fff;font-size:20px}li{padding-bottom:10px;line-height:150%}.left{float:left}.right{float:right}.hide{display:none}#ajaxPopup{position:absolute;width:750px;height:550px;background-color:#fff;top:68px;left:50%;margin-left:-375px;box-shadow:0 1px 2px 0 rgba(0,0,0,0.2);background-color:#93B1C6}#ajaxPopup legend{width:720px;padding:15px;color:#fff;background-color:#000;margin:0}#ajaxPopup fieldset{border:0;margin:0;padding:0}#ajaxPopup label{width:160px;color:#000;line-height:48px}#ajaxPopup p{margin:20px}#ajaxPopup input{width:50%}#ajaxPopup button{position:absolute;bottom:0}#ajaxPopup .bottom{position:absolute;bottom:0}#ajaxPopup .full_width{left:0;right:0}.margin_default{margin:10px}.header span{font-size:100px}.headerbar{background-color:#E7EAEF}.footer{width:100%:margin:auto;height:40px;background-color:#ddd;border-top:1px solid #aaa;border-bottom:1px solid #aaa}.footerbar{background-color:#E7EAEF;border-top:1px solid #D2D2D2;border-bottom:1px solid #D2D2D2;margin-top:60px}.pageFooter{clear:both}.pageHeader{padding:20px;color:#fff;font-size:24px}.pagination{height:40px;font-size:16px}.pagination li.active{background-color:#0a2024}.pagination li{float:left;list-style-type:none;margin-left:12px;background-color:#7eabb8;padding:2px;border:2px solid #000;border-radius:6px}.pagination li:hover{background-color:#0a2128}.pagination li a{text-decoration:none;color:#000}.on{background-color:#1e424c!important}.clear{clear:both}table{width:100%;background-color:#eee;font-size:11px;border-collapse:collapse;border-spacing:0;box-shadow:0 1px 3px 0 rgba(0,0,0,0.12),0px 1px 2px 0 rgba(0,0,0,0.24)}table tr{transition:all .3s ease 0s}table th{padding:16px}table td{padding:16px;border-bottom:1px solid rgba(0,0,0,0.12)}table caption{font-size:16px}tbody tr:nth-child(odd){background-color:#eee;font-size:11px}.tabrow1(background-color:#eee;) #topbar{position:relative;position:absolute;top:0;width:100%;z-index:10}.hover:hover{background-color:#9fa8da}.hover:hover{background-color:#9fa8da}.hover-expand:hover .children{display:block}.copyright{float:right;margin-top:20px;color:#fff}.tile-right{margin-top:20px;width:230px;float:right;margin-right:20px}.tile-right img{float:right}.tile-image{float:right;clear:right}#headerstrip{overflow:hidden;line-height:1px;position:absolute;left:0;right:0;height:68px;top:0;background-color:#00232D}#headerstrip .navstrip{box-shadow:none;margin:10px;height:48px;background-color:#00232D}#headerstrip .navstripleft{padding:0}#headerstrip .mini-logo-text{line-height:25px;position:absolute;left:56px;padding-top:12px;font-size:22px;color:#fff;font-weight:bold;padding-left:10px}#headerstrip .mini_logo{position:absolute;width:48px;height:48px}#headerstrip .mini-logo:hover{transition:ease-in-out;-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;-o-transform-origin:50% 50%;transform-origin:50% 50%;height:48px;width:48px;-webkit-animation:spin 2s linear infinite;-moz-animation:spin 2s linear infinite;animation:spin 2s linear infinite}#headerstrip .middle{}#menubar{margin-top:108px}#menubar nav{height:48px;background-color:#0087A8}#menubar nav ul{width:100%;height:100%}#menubar nav li{margin:10px}@-moz-keyframes spin{100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{100%{-webkit-transform:rotate(360deg)}}@keyframes spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.menu{position:absolute;left:0;right:0;height:408px;top:68px;background-color:#00232D;z-index:-1}.menu ul{width:960px;margin:auto;height:40px;padding-left:20px;background-color:#0087A8}.menu li{width:130px;float:left;list-style-type:none;margin-top:10px;padding:00px;text-align:center}.menu li:hover{width:130px;float:left;list-style-type:none;border-bottom:4px solid #1C4085}.menu a{color:#fff;font-weight:bold;text-decoration:none}.menu li:hover{}.page{margin:auto;margin-top:28px;padding-bottom:48px;background-color:#0087A8}.page .pageSection{margin-left:20px}.page .messages{color:#fff;border:10px solid #0087A8;background-color:#00232D;font-weight:bold}.page .messages li{padding:10px}.columns{float:right;clear:right;width:460px;margin-left:20px;margin-bottom:20px}.google-groups-signup{width:300px;float:left}.google-groups-signup input{margin-top:20px;width:290px;padding-left:10px}.google-groups-signup a{color:#fff;width:282px}.banner-slide{position:absolute;width:700px;margin:20px 20px 20px 0}.banner-slide ul{position:relative;overflow:hidden;width:700px;height:300px;margin:0}.banner-slide li{position:absolute;left:0;top:0;list-style-type:none;padding:0;margin:0}.banner-slide .button{background-color:#0087A8;border-radius:50%;opacity:.4}.banner-slide .content{color:#111;position:absolute;top:250px;width:100%;background-color:#eee;opacity:.4}.banner-slide .left{text-align:left;padding:6px;font-size:48px;color:#fff;position:absolute;top:122px;left:0;width:60px;height:60px;background-color:transparent}.banner-slide .right{text-align:right;padding:6px;font-size:48px;color:#fff;position:absolute;top:122px;right:15px;width:60px;height:60px;background-color:transparent}.slide-button{background-image:url('static/images/css/sprite-navigation-white.png')}.slide{position:absolute;left:0}.slide.ng-hide-add{left:0;opacity:1}.slide.ng-hide-add-active{transition:.9s linear all;opacity:0}.slide.ng-hide-remove{left:0;opacity:0}.slide.ng-hide-remove-active{transition:.9s linear all;opacity:1}.slide.ng-leave.ng-leave-active,.slide.ng-enter{transition:.5s linear all;left:0;opacity:0}.slide.ng-leave,.slide.ng-enter.ng-enter-active{transition:.5s linear all;left:0;opacity:1}.bullet-list li{margin:0;margin-left:10px;line-height:100%}.tile{position:relative;margin:0}.tile-border{background-color:#eee;margin-right:20px;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26)}.tile-img{height:200px;overflow:hidden;background-repeat:no-repeat;background-position:center;background-image:url('/static/images/background.png')}.tile header{background-color:#00232D;width:100%;bottom:20px;top:220px;overflow:auto;left:20px;right:20px;text-align:left;line-height:150%;font-size:12px}.tile h2{margin-left:25px;line-height:150%;font-size:12px;margin-right:20px}.tile p{margin-left:25px}.tile header a{color:#fff}.tile .content{overflow:hidden;bottom:20px;top:220px;overflow:auto;left:20px;right:20px;text-align:justify;line-height:20px;height:106px;font-size:12px}#footertop{background-color:#00232D;height:48px}#footerbottom{background-color:#0087A8;height:300px}#footerbottom div.container{margin:auto;background-color:#0087A8;height:250px;width:960px}.twitter-feed{width:460px;margin:20px}.social-chat{width:100%;height:480px;position:relative}.social-chat .contain{left:0;right:0;height:480px;position:absolue;margin:20px}.social-chat iframe{display:block;border:0;width:100%;height:100%}.social{z-index:1;position:absolute;right:0;top:0;margin-top:0}.social .socbtn{line-height:0;float:left;margin-left:20px;margin-top:20px}#login_box{width:500px;margin:auto;position:relative}#login_box p{color:#fff;padding:0;margin:0}#login_box label{display:block;margin:20px 0 20px}#login_box input{margin:20px 0 0;float:none;width:100%}#login_box button{margin:20px 0 0;float:left;width:100%}#login_box .providers{margin:20px 0 20px;height:48px;height:35px}#login_box .providers a{float:left;margin-right:30px}.members .stats{}.members .tile{width:220px;float:left}.members .tile-img{margin:auto;width:200px}.members .badge{width:32px;height:32px;margin:0;margin-top:5px}#member_navigation{z-index:2;position:fixed;top:68px;left:0;width:180px;height:100%}#member_navigation a{color:#fff;font-weight:bold;text-decoration:none}#member_navigation ul{padding:0;margin:0;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26)}#member_navigation li{margin:0;padding:10px;background-color:#0087A8;list-style-type:none}#member_navigation li:hover{background-color:#E7EAEF}.action-bar{overflow:hidden;position:fixed;right:50px;bottom:50px;width:65px;height:70px}.action-bar:hover{height:260px}.action-bar .container{position:absolute;left:0;bottom:0;width:62px;min-width:62px;max-width:62px;padding-bottom:5px}.action-bar-small{overflow:hidden;position:absolute;right:0;top:40px;width:32px;height:32px}.action-bar .action-bar-button{margin-top:20px}.action-bar-button{display:block;padding:19px;background-color:#FF2670;border-radius:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26);z-index:5}.action-bar-button-small{display:block;padding:19px;background-color:#FF2670;border-radius:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26);z-index:5}.closePopup{position:absolute;top:12px;right:12px;background-color:#FF2670;border-radius:100%;box-shadow:0 2px 5px 0 rgba(0,0,0,0.26);z-index:5}#membercard{color:#000;background-color:#8C50A5;border-radius:14px;box-shadow:0 2px 5px 0 rgba(0,0,0,0.5);background-image:url('/static/images/membership_card_background.png');width:430px;height:240px;margin-left:20px;text-shadow:1px 1px #FFF;position:relative;float:right}#membercard label{color:#000}#membercard label.active{color:#000!important}#membercard .row{margin-bottom:0}#membercard .input-field{margin:0}#membercard .date{position:absolute;margin:25px;top:0;left:0}#membercard p{margin:0}#membercard .container{position:relative;top:50%;width:100%}#membercard .middle{color:#000;position:absolute;top:-38px;width:100%;text-align:center;font-size:28px}#membercard legend{margin:0;font-weight:strong;height:40px}#membercard fieldset{position:absolute;top:0;left:0;right:0;padding:0;margin:6px;border:0;height:240px}.calendar{width:230px;height:300px;overflow:auto}.calendar ul{list-style:none;padding:0;margin:0}.calendar li{font-size:14px;padding:6px}.calendar li:first-child{color:#fff;background-color:#00232D}.calendar .but{width:80px;text-align:center}.but{border:1px solid #000a0d;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;font-size:12px;font-family:arial,helvetica,sans-serif;padding:10px 10px 10px 10px;text-decoration:none;display:inline-block;text-shadow:-1px -1px 0 rgba(0,0,0,0.3);font-weight:bold;color:#FFF;background-color:#003645;background-image:-webkit-gradient(linear,left top,left bottom,from(#003645),to(#00232D));background-image:-webkit-linear-gradient(top,#003645,#00232D);background-image:-moz-linear-gradient(top,#003645,#00232D);background-image:-ms-linear-gradient(top,#003645,#00232D);background-image:-o-linear-gradient(top,#003645,#00232D)}#card-number{border:1px solid #333;-webkit-transition:border-color 160ms;transition:border-color 160ms;background-color:#fff;color:#000;padding-left:10px}#card-number.braintree-hosted-fields-focused{border-color:#777;background-color:#fff;color:#000;padding-left:10px}#card-number.braintree-hosted-fields-invalid{border-color:tomato;background-color:#fff;color:#000;padding-left:10px}#card-number.braintree-hosted-fields-valid{border-color:limegreen;background-color:#fff;color:#000;padding-left:10px} \ No newline at end of file diff --git a/website/tools/list_registered_members.py b/website/tools/list_registered_members.py index e600a3b..c03fdd0 100644 --- a/website/tools/list_registered_members.py +++ b/website/tools/list_registered_members.py @@ -1,15 +1,42 @@ import os import sys +sys.path.insert(0, os.path.abspath('../../')) sys.path.append(os.path.abspath('../../')) from website.config.settings import * -from website.libs.payments import payment, gocardless_provider, paypal_provider +from website.libs.payments import payment, gocardless_provider, paypal_provider, braintree_provider + +#list go cardless subscriptions +print('gocardless subscriptions') gocardless = gocardless_provider() +gocardless.create_subscription( + amount=20.00, + name='test name', + redirect_success='http://localhost/', + redirect_failure='http://localhost/', + interval_unit='month', + interval_length='1') for user in gocardless.fetch_subscriptions(): print(user) +print('braintree subscriptions') + +braintree = braintree_provider() +print (braintree.create_subscription( + amount=20.00, + name='test name', + redirect_success='http://localhost/', + redirect_failure='http://localhost/', + interval_unit='month', + interval_length='1')) + +for user in braintree.fetch_subscriptions(): + print(user) + + + # paypal = paypal_provider() # for user in paypal.fetch_subscriptions(): diff --git a/website/widgets/member_card.py b/website/widgets/member_card.py index b137601..3cad0ec 100644 --- a/website/widgets/member_card.py +++ b/website/widgets/member_card.py @@ -31,7 +31,7 @@ class control(base_widget_extended):