def establish_mandate(): jamla = get_jamla() jamlaApp = Jamla() jamlaApp.load(jamla=jamla) if jamlaApp.has_connected("gocardless") is False: dashboard_url = url_for("admin.dashboard") return """<h1>Shop not set-up yet</h1> The shop owner first needs to login to their <a href="{}">dahboard</a>, and connect GoCardless to their shop. Once this has been completed, you will be able to order. """.format(dashboard_url) # lookup the customer with sid and get their relevant details sid = session["sid"] db = get_db() res = db.execute("SELECT * FROM person p WHERE p.sid = ?", (sid, )).fetchone() logger.info("Person lookup: %s", res) # validate that hasInstantPaid is true for the customer gocclient = gocardless_pro.Client( access_token=jamlaApp.get_secret("gocardless", "access_token"), environment=jamla["payment_providers"]["gocardless"]["environment"], ) description = " ".join([jamla["company"]["name"], session["package"]])[0:100] redirect_flow = gocclient.redirect_flows.create( params={ "description": description, "session_token": sid, "success_redirect_url": current_app.config["SUCCESS_REDIRECT_URL"], "prefilled_customer": { "given_name": res["given_name"], "family_name": res["family_name"], "address_line1": res["address_line1"], "city": res["city"], "postal_code": res["postal_code"], "email": res["email"], }, }) # Hold on to this ID - we'll need it when we # "confirm" the dedirect flow later print("ID: {} ".format(redirect_flow.id)) print("URL: {} ".format(redirect_flow.redirect_url)) # Check if we're inside an iframe, if yes redirect to pop-up # Issue https://github.com/Subscribie/subscribie/issues/128 if request.args.get('inside_iframe', 'False') == "True": inside_iframe = True return render_template("iframe_new_window_redirect.html", redirect_url=redirect_flow.redirect_url, jamla=jamla) return '<a href="{}" target="_blank">Continue</a>'.format( redirect_flow.redirect_url) else: return redirect(redirect_flow.redirect_url)
def retry_payment(payment_id): payment_provider = PaymentProvider.query.first() gocclient = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment, ) r = gocclient.payments.retry(payment_id) return "Payment (" + payment_id + " retried." + str(r)
def retry_payment(payment_id): jamlaApp = Jamla() jamla = jamlaApp.load(src=app.config['JAMLA_PATH']) gocclient = gocardless_pro.Client( access_token=get_secret('gocardless', 'access_token'), environment=jamla['payment_providers']['gocardless']['environment']) r = gocclient.payments.retry(payment_id) return "Payment (" + payment_id + " retried." + str(r)
def retry_payment(payment_id): jamla = get_jamla() jamlaapp = jamla() jamlaapp.load(jamla=jamla) gocclient = gocardless_pro.Client( access_token=get_secret("gocardless", "access_token"), environment=jamla["payment_providers"]["gocardless"]["environment"], ) r = gocclient.payments.retry(payment_id) return "Payment (" + payment_id + " retried." + str(r)
def push_payments(): """ Push payments to Penguin. Assume a gocardless endpoint for now. """ jamla = get_jamla() jamlaApp = Jamla() jamlaApp.load(jamla=jamla) gocclient = gocardless_pro.Client( access_token=get_secret("gocardless", "access_token"), environment=jamla["payment_providers"]["gocardless"]["environment"], ) # Loop customers for payments in gocclient.payments.list().records: ##Loop each payment within payment response body response = payments.api_response.body for payment in response["payments"]: logging.info(payment) logging.info("The payment status is: %s", payment["status"]) logging.info("Creating transaction to penguin") title = "a transaction title" try: payout_id = payment["links"]["payout"] except: payout_id = None fields = { "title": title, "field_gocardless_payment_id": payment["id"], "field_gocardless_payout_id": payout_id, "field_gocardless_amount": payment["amount"], "field_gocardless_payment_status": payment["status"], "field_mandate_id": payment["links"]["mandate"], "field_gocardless_subscription_id": payment["links"]["subscription"], "field_gocardless_amount_refunded": payment["amount_refunded"], "field_gocardless_charge_date": payment["charge_date"], "field_gocardless_created_at": payment["created_at"], "field_gocardless_creditor_id": payment["links"]["creditor"], } Rest.post(entity="transaction", fields=fields) return "Payments have been pushed"
def push_payments(): """ Push payments to Penguin. Assume a gocardless endpoint for now. """ jamlaApp = Jamla() jamla = jamlaApp.load(src=app.config['JAMLA_PATH']) gocclient = gocardless_pro.Client( access_token=get_secret('gocardless', 'access_token'), environment=jamla['payment_providers']['gocardless']['environment']) #Loop customers for payments in gocclient.payments.list().records: ##Loop each payment within payment response body response = payments.api_response.body for payment in response['payments']: print payment print payment['status'] print "##" # Push to Penguin print "Creating transaction to penguin.." title = "a transaction title" try: payout_id = payment['links']['payout'] except: payout_id = None fields = { 'title': title, 'field_gocardless_payment_id': payment['id'], 'field_gocardless_payout_id': payout_id, 'field_gocardless_amount': payment['amount'], 'field_gocardless_payment_status': payment['status'], 'field_mandate_id': payment['links']['mandate'], 'field_gocardless_subscription_id': payment['links']['subscription'], 'field_gocardless_amount_refunded': payment['amount_refunded'], 'field_gocardless_charge_date': payment['charge_date'], 'field_gocardless_created_at': payment['created_at'], 'field_gocardless_creditor_id': payment['links']['creditor'] } Rest.post(entity='transaction', fields=fields) return "Payments have been pushed"
def establish_mandate(): company = Company.query.first() item = Item.query.filter_by(uuid=session["item"]).first() payment_provider = PaymentProvider.query.first() if payment_provider.gocardless_active is False: dashboard_url = url_for("admin.dashboard") return """<h1>Shop not set-up yet</h1> The shop owner first needs to login to their <a href="{}">dahboard</a>, and connect GoCardless to their shop. Once this has been completed, you will be able to order. """.format(dashboard_url) # Get person from session person = Person.query.get(session["person_id"]) # validate that hasInstantPaid is true for the customer gocclient = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment, ) description = " ".join([company.name, item.title])[0:100] redirect_flow = gocclient.redirect_flows.create( params={ "description": description, "session_token": person.sid, "success_redirect_url": current_app.config["SUCCESS_REDIRECT_URL"], "prefilled_customer": { "given_name": person.given_name, "family_name": person.family_name, "address_line1": person.address_line1, "city": person.city, "postal_code": person.postal_code, "email": person.email, }, }) # Hold on to this ID - we'll need it when we # "confirm" the dedirect flow later print("ID: {} ".format(redirect_flow.id)) print("URL: {} ".format(redirect_flow.redirect_url)) # Check if we're inside an iframe, if yes redirect to pop-up # Issue https://github.com/Subscribie/subscribie/issues/128 if request.args.get('inside_iframe', 'False') == "True": inside_iframe = True return render_template("iframe_new_window_redirect.html", redirect_url=redirect_flow.redirect_url) return '<a href="{}" target="_blank">Continue</a>'.format( redirect_flow.redirect_url) else: return redirect(redirect_flow.redirect_url)
def get_subscription_status(gocardless_subscription_id) -> str: status_on_error = "Unknown" payment_provider = PaymentProvider.query.first() client = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment) try: response = client.subscriptions.get(gocardless_subscription_id) return response.status if hasattr(response, "status") else status_on_error except Exception as e: logging.error(e) return status_on_error
def pause_gocardless_subscription(subscription_id): """Pause a GoCardless subscription""" payment_provider = PaymentProvider.query.first() gocclient = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment, ) try: req = gocclient.subscriptions.pause(subscription_id) except gocardless_pro.errors.InvalidStateError as e: return jsonify(error=e.message) flash("Subscription paused") if 'goback' in request.args: return redirect(request.referrer) return jsonify(message="Subscription paused", subscription_id=subscription_id)
def upcoming_payments(): previous_page_cursor = request.args.get('previous', None) next_page_cursor = request.args.get('next', None) payment_provider = PaymentProvider.query.first() client = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment, ) # Get latest payments payments = client.payments.list(params={"limit": 10}).records # Paginate try: latest_payment_id = payments[-1].id if next_page_cursor: payments = client.payments.list(params={ "after": next_page_cursor, "limit": 10 }).records next_page_cursor = payments[-1].id previous_payments = client.payments.list(params={ "before": next_page_cursor, "limit": 10 }).records previous_page_cursor = previous_payments[-1].id except IndexError: payments = [] # No payments yet # Store / Update transactions table for payment in payments: store_gocardless_transaction(payment.id) return render_template('admin/upcoming_payments.html', payments=payments, datetime=datetime, next_page_cursor=next_page_cursor, previous_page_cursor=previous_page_cursor)
def push_mandates(): jamlaApp = Jamla() jamla = jamlaApp.load(src=app.config['JAMLA_PATH']) gocclient = gocardless_pro.Client( access_token=get_secret('gocardless', 'access_token', jamla), environment=jamla['payment_providers']['gocardless']['environment']) #Loop mandates for mandate in gocclient.mandates.list().records: print "##" # Push to Penguin print "Pushing mandate to penguin.." title = mandate.id fields = { 'title': title, 'field_gocardless_created_at': mandate.created_at, 'field_gocardless_cust_bank_id': mandate.attributes['links']['customer_bank_account'], 'field_gocardless_mandate_creditr': mandate.attributes['links']['creditor'], 'field_gocardless_mandate_cust_id': mandate.attributes['links']['customer'], 'field_gocardless_mandate_id': mandate.id, 'field_gocardless_mandate_ref': mandate.reference, 'field_gocardless_mandate_scheme': mandate.scheme, 'field_gocardless_mandate_status': mandate.status, 'field_gocardless_metadata': str(mandate.metadata), 'field_gocardless_new_mandate_id': '', 'field_gocardless_pmts_req_approv': mandate.payments_require_approval, 'field_gocardless_next_pos_charge': mandate.next_possible_charge_date } Rest.post(entity='mandate', fields=fields) return "Mandates pushed"
def cancel_mandates(email): """Cancel all mandates associated with a given email""" jamla = get_jamla() if "confirm" in request.args: # Get all mandates associated with <email> # Then cancel them transactions = get_transactions() partner_madates = [] for transaction in transactions: # Match email to mandates if transaction.mandate['links']['customer']['email'] == email \ and transaction.mandate['status'] == 'active': partner_madates.append(transaction.mandate) if len(partner_madates) > 0: gocclient = gocardless_pro.Client( access_token=jamla["payment_providers"]["gocardless"] ["access_token"], environment=jamla["payment_providers"]["gocardless"] ["environment"], ) for mandate in partner_madates: # Cancel each mandate for given email removed = False try: req = gocclient.mandates.cancel(mandate['id']) flash("Mandate canceled for {}".format(email)) flash("The mandate ID was: {}".format(mandate['id'])) removed = True except gocardless_pro.errors.InvalidStateError: removed = True flash("Mandate already canceled for {}".format(email)) flash("The mandate ID was: {}".format(mandate['id'])) if removed: # Remove from local mandates list refresh_ssot(resource='customers') return redirect(url_for("admin.customers")) return render_template("admin/cancel_mandates_confirm.html", email=email, jamla=jamla)
def establish_mandate(): jamlaApp = Jamla() jamla = jamlaApp.load(app.config['JAMLA_PATH']) #lookup the customer with sid and get their relevant details sid = session['sid'] con = sqlite3.connect(app.config["DB_FULL_PATH"]) cur = con.cursor() cur.execute("SELECT * FROM person p WHERE p.sid = ?", (sid, )) res = cur.fetchone() print res con.close() # validate that hasInstantPaid is true for the customer gocclient = gocardless_pro.Client( access_token=jamlaApp.get_secret('gocardless', 'access_token'), environment=jamla['payment_providers']['gocardless']['environment']) description = ' '.join([jamla['company']['name'], session['package']])[0:100] redirect_flow = gocclient.redirect_flows.create( params={ "description": description, "session_token": sid, "success_redirect_url": app.config['SUCCESS_REDIRECT_URL'], "prefilled_customer": { "given_name": res[2], "family_name": res[3], "address_line1": res[4], "city": res[5], "postal_code": res[6], "email": res[7] } }) # Hold on to this ID - we'll need it when we # "confirm" the dedirect flow later print("ID: {} ".format(redirect_flow.id)) print("URL: {} ".format(redirect_flow.redirect_url)) return redirect(redirect_flow.redirect_url)
def store_gocardless_transaction(gocardless_payment_id): """Store GoCardless payment in transactions table""" payment_provider = PaymentProvider.query.first() gocclient = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment, ) payment = gocclient.payments.get(gocardless_payment_id) # Check if there's an existing payment record in transactions table transaction = Transaction.query.filter_by( external_id=gocardless_payment_id).first() if transaction is None: # No existing transaction found, so fetch payment info from GoCardless # Store as transaction transaction = Transaction() transaction.amount = payment.amount transaction.payment_status = payment.status transaction.comment = str(payment.metadata) transaction.external_id = gocardless_payment_id transaction.external_src = "gocardless" # Find related subscription if exists if payment.links.subscription: subscription_id = payment.links.subscription subscription = Subscription.query.filter_by( gocardless_subscription_id=subscription_id).first() if subscription is not None: transaction.subscription = subscription try: transaction.person = subscription.person except AttributeError: # A transaction may not have a person pass # Update payment_status to gocardless latest status transaction.payment_status = payment.status database.session.add(transaction) database.session.commit() # Save/update transaction in transactions table return transaction
def on_complete_mandate(): item = Item.query.filter_by(uuid=session["item"]).first() payment_provider = PaymentProvider.query.first() redirect_flow_id = request.args.get("redirect_flow_id") logger.info("Recieved flow ID: %s ", redirect_flow_id) logger.info( "Setting up client environment as: %s", payment_provider.gocardless_environment, ) gocclient = gocardless_pro.Client( access_token=payment_provider.gocardless_access_token, environment=payment_provider.gocardless_environment, ) try: redirect_flow = gocclient.redirect_flows.complete( redirect_flow_id, params={"session_token": session["sid"]}) logger.info("Confirmation URL: %s", redirect_flow.confirmation_url) # Save this mandate & customer ID for the next section. logger.info("Mandate: %s", redirect_flow.links.mandate) logger.info("Customer: %s", redirect_flow.links.customer) session["gocardless_mandate_id"] = redirect_flow.links.mandate session["gocardless_customer_id"] = redirect_flow.links.customer # Store customer sid = session["sid"] now = datetime.datetime.now() mandate = redirect_flow.links.mandate customer = redirect_flow.links.customer flow = redirect_flow_id logger.info( "Creating subscription with amount: %s", str(item.monthly_price), ) logger.info( "Creating subscription with name: %s", item.title, ) logger.info("Item session is set to: %s", str(session["item"])) logger.info("Mandate id is set to: %s", session["gocardless_mandate_id"]) # If days_before_first_charge is set, apply start_date adjustment try: days_before_first_charge = item.days_before_first_charge if days_before_first_charge == 0 or days_before_first_charge == '': start_date = None else: today = date.today() enddate = today + datetime.timedelta( days=int(days_before_first_charge)) start_date = enddate.strftime('%Y-%m-%d') except KeyError: start_date = None # Create subscription print("Creating subscription") # Store Subscription against Person locally person = database.session.query(Person).filter_by( email=session['email']).first() subscription = Subscription(sku_uuid=session['package'], person=person) database.session.add(subscription) database.session.commit() # Add subscription id to session session["subscription_id"] = subscription.id # Submit to GoCardless as subscription gc_subscription = gocclient.subscriptions.create( params={ "amount": item.monthly_price, "currency": "GBP", "name": item.title, "interval_unit": "monthly", "metadata": { "subscribie_subscription_uuid": subscription.uuid }, "links": { "mandate": session["gocardless_mandate_id"] }, "start_date": start_date }) # Get first charge date & store in session first_charge_date = gc_subscription.upcoming_payments[0]['charge_date'] first_charge_amount = gc_subscription.upcoming_payments[0]['amount'] session['first_charge_date'] = str( datetime.datetime.strptime(first_charge_date, '%Y-%m-%d').strftime('%d/%m/%Y')) session['first_charge_amount'] = first_charge_amount # Store GoCardless subscription id subscription.gocardless_subscription_id = gc_subscription.id database.session.add(subscription) database.session.commit() except Exception as e: logger.error(e) if isinstance(e, gocardless_pro.errors.InvalidStateError): if e.error["type"] == "invalid_state": # Allow pass through if redirect flow already completed if e.errors[0]["reason"] == "redirect_flow_already_completed": pass # Display a confirmation page to the customer, telling them # their Direct Debit has been set up. return redirect(current_app.config["THANKYOU_URL"])
def on_complete_mandate(): jamlaApp = Jamla() jamla = jamlaApp.load(app.config['JAMLA_PATH']) redirect_flow_id = request.args.get('redirect_flow_id') print("Recieved flow ID: {} ".format(redirect_flow_id)) print "Setting up client environment as: " + jamla['payment_providers'][ 'gocardless']['environment'] gocclient = gocardless_pro.Client( access_token=jamlaApp.get_secret('gocardless', 'access_token'), environment=jamla['payment_providers']['gocardless']['environment']) try: redirect_flow = gocclient.redirect_flows.complete( redirect_flow_id, params={"session_token": session['sid']}) print("Confirmation URL: {}".format(redirect_flow.confirmation_url)) # Save this mandate & customer ID for the next section. print("Mandate: {}".format(redirect_flow.links.mandate)) print("Customer: {}".format(redirect_flow.links.customer)) session['gocardless_mandate_id'] = redirect_flow.links.mandate session['gocardless_customer_id'] = redirect_flow.links.customer # Store customer sid = session['sid'] now = datetime.datetime.now() mandate = redirect_flow.links.mandate customer = redirect_flow.links.customer flow = redirect_flow_id con = sqlite3.connect(app.config['DB_FULL_PATH']) cur = con.cursor() cur.execute("SELECT * FROM person WHERE sid = ?", (sid, )) row = cur.fetchone() customerName = row[2] + " " + row[3] customerAddress = row[4] + ", " + row[5] + ", " + row[6] customerEmail = row[7] customerPhone = row[8] chosenPackage = row[9] customerExistingLine = row[10] customerExistingNumber = row[11] print "Creating subscription with amount: " + str( jamlaApp.sku_get_monthly_price(session['plan'])) print "Creating subscription with name: " + jamlaApp.sku_get_title( session['plan']) print "Plan session is set to: " + str(session['plan']) print "Mandate id is set to: " + session['gocardless_mandate_id'] # Create subscription gocclient.subscriptions.create( params={ "amount": jamlaApp.sku_get_monthly_price(session['plan']), "currency": "GBP", "name": jamlaApp.sku_get_title(session['plan']), "interval_unit": "monthly", "metadata": { "sku": session['plan'] }, "links": { "mandate": session['gocardless_mandate_id'] } }) except Exception as e: print e if isinstance(e, gocardless_pro.errors.InvalidStateError): if e.error['type'] == 'invalid_state': # Allow pass through if redirect flow already completed if e.errors[0]['reason'] == "redirect_flow_already_completed": pass # Display a confirmation page to the customer, telling them # their Direct Debit has been set up. return redirect(app.config['THANKYOU_URL'])
def on_complete_mandate(): jamla = get_jamla() jamlaApp = Jamla() jamlaApp.load(jamla=jamla) redirect_flow_id = request.args.get("redirect_flow_id") logger.info("Recieved flow ID: %s ", redirect_flow_id) logger.info( "Setting up client environment as: %s", jamla["payment_providers"]["gocardless"]["environment"], ) gocclient = gocardless_pro.Client( access_token=jamlaApp.get_secret("gocardless", "access_token"), environment=jamla["payment_providers"]["gocardless"]["environment"], ) try: redirect_flow = gocclient.redirect_flows.complete( redirect_flow_id, params={"session_token": session["sid"]}) logger.info("Confirmation URL: %s", redirect_flow.confirmation_url) # Save this mandate & customer ID for the next section. logger.info("Mandate: %s", redirect_flow.links.mandate) logger.info("Customer: %s", redirect_flow.links.customer) session["gocardless_mandate_id"] = redirect_flow.links.mandate session["gocardless_customer_id"] = redirect_flow.links.customer # Store customer sid = session["sid"] now = datetime.datetime.now() mandate = redirect_flow.links.mandate customer = redirect_flow.links.customer flow = redirect_flow_id con = sqlite3.connect(current_app.config["DB_FULL_PATH"]) cur = con.cursor() cur.execute("SELECT * FROM person WHERE sid = ?", (sid, )) row = cur.fetchone() customerName = row[2] + " " + row[3] customerAddress = row[4] + ", " + row[5] + ", " + row[6] customerEmail = row[7] customerPhone = row[8] chosenPackage = row[9] customerExistingLine = row[10] customerExistingNumber = row[11] logger.info( "Creating subscription with amount: %s", str(jamlaApp.sku_get_monthly_price(session["plan"])), ) logger.info( "Creating subscription with name: %s", jamlaApp.sku_get_title(session["plan"]), ) logger.info("Plan session is set to: %s", str(session["plan"])) logger.info("Mandate id is set to: %s", session["gocardless_mandate_id"]) # If days_before_first_charge is set, apply start_date adjustment itemIndex = jamlaApp.sku_get_index(session['plan']) try: days_before_first_charge = jamla['items'][itemIndex][ 'days_before_first_charge'] if days_before_first_charge == 0 or days_before_first_charge == '': start_date = None else: today = date.today() enddate = today + datetime.timedelta( days=int(days_before_first_charge)) start_date = enddate.strftime('%Y-%m-%d') except KeyError: start_date = None # Create subscription print("Creating subscription") gocclient.subscriptions.create( params={ "amount": int(jamlaApp.sku_get_monthly_price(session["plan"])), "currency": "GBP", "name": jamlaApp.sku_get_title(session["plan"]), "interval_unit": "monthly", "metadata": { "sku": session["plan"] }, "links": { "mandate": session["gocardless_mandate_id"] }, "start_date": start_date }) except Exception as e: logger.error(e) if isinstance(e, gocardless_pro.errors.InvalidStateError): if e.error["type"] == "invalid_state": # Allow pass through if redirect flow already completed if e.errors[0]["reason"] == "redirect_flow_already_completed": pass # Display a confirmation page to the customer, telling them # their Direct Debit has been set up. return redirect(current_app.config["THANKYOU_URL"])