示例#1
0
def delete_item_by_sku(sku):
    """Archive (dont actually delete) an item"""
    jamla = get_jamla()
    # Filter archived items
    jamlaApp = Jamla()
    jamla = jamlaApp.filter_archived_items(jamla)

    jamlaApp = Jamla()
    jamlaApp.load(jamla=get_jamla())
    itemIndex = jamlaApp.sku_get_index(sku)
    if "confirm" in request.args:
        confirm = False
        return render_template(
            "admin/delete_jamla_item_choose.html",
            jamla=jamla,
            itemSKU=sku,
            confirm=False,
        )
    if itemIndex is not False:
        # Perform removal
        jamla["items"][itemIndex]['archived'] = True
        fp = open(current_app.config["JAMLA_PATH"], "w")
        yaml.safe_dump(jamla, fp, default_flow_style=False)

    flash("Item deleted.")
    return render_template("admin/delete_jamla_item_choose.html", jamla=jamla)
示例#2
0
def charge_up_front():
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    charge = {}
    charge["amount"] = session["upfront_cost"]
    charge["currency"] = "GBP"

    sid = session["sid"]

    db = get_db()
    res = db.execute("SELECT * FROM person p WHERE p.sid = ?",
                     (sid, )).fetchone()
    try:
        stripe.api_key = jamla["payment_providers"]["stripe"]["secret_key"]
        customer = stripe.Customer.create(email=res["email"],
                                          source=request.form["stripeToken"])

        charge = stripe.Charge.create(
            customer=customer.id,
            amount=charge["amount"],
            currency=charge["currency"],
            description="Subscribie",
        )
    except stripe.error.AuthenticationError as e:
        return str(e)
    if jamlaApp.requires_subscription(session["package"]):
        return redirect(url_for("views.establish_mandate"))
    else:
        return redirect(
            url_for("views.thankyou", _scheme="https", _external=True))
示例#3
0
def thankyou():
    jamla = get_jamla()
    # Store note to seller if in session
    if session.get('note_to_seller', False) is not False:
        tdb = dingdb(database=current_app.config["DB_FULL_PATH"])
        tdb.putDing(str(uuid4()),
                    'orderNote',
                    'orderNote',
                    data=[{
                        'key': 'email',
                        'value': session["email"]
                    }, {
                        'key': 'note',
                        'value': session["note_to_seller"]
                    }])
    # Send journey_complete signal
    journey_complete.send(current_app._get_current_object(),
                          email=session["email"])
    try:
        logger.info("The Mandate id is: %s",
                    str(session["gocardless_mandate_id"]))
        logger.info("The GC Customer id is: %s",
                    str(session["gocardless_customer_id"]))
    except KeyError:
        logger.warning("No mandate for this transaction")
        logger.warning(
            "Maybe OK as not all items require a direct debit mandate")
    finally:
        return render_template("thankyou.html",
                               jamla=jamla,
                               pages=jamla['pages'])
示例#4
0
def choose():
    jamla = get_jamla()
    # Filter archived items
    jamlaApp = Jamla()
    jamla = jamlaApp.filter_archived_items(jamla)

    return render_template("choose.html", jamla=jamla, pages=jamla['pages'])
示例#5
0
def connect_stripe_manually():
    form = StripeConnectForm()
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    if jamlaApp.has_connected("stripe"):
        stripe_connected = True
    else:
        stripe_connected = False
    if form.validate_on_submit():
        publishable_key = form.data["publishable_key"].strip()
        secret_key = form.data["secret_key"].strip()
        jamla["payment_providers"]["stripe"][
            "publishable_key"] = publishable_key
        jamla["payment_providers"]["stripe"]["secret_key"] = secret_key
        # Overwrite jamla file with gocardless access_token
        fp = open(current_app.config["JAMLA_PATH"], "w")
        yaml.safe_dump(jamla, fp, default_flow_style=False)
        session["stripe_publishable_key"] = publishable_key
        # Set stripe public key JS
        return redirect(url_for("admin.dashboard"))
    else:
        return render_template(
            "admin/connect_stripe_manually.html",
            form=form,
            jamla=jamla,
            stripe_connected=stripe_connected,
        )
示例#6
0
def gocardless_oauth_complete():
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    flow = OAuth2WebServerFlow(
        client_id=current_app.config["GOCARDLESS_CLIENT_ID"],
        client_secret=current_app.config["GOCARDLESS_CLIENT_SECRET"],
        scope="read_write",
        # You'll need to use exactly the same redirect URI as in the last
        # step
        redirect_uri="http://127.0.0.1:5000/connect/gocardless/oauth/complete",
        auth_uri="https://connect-sandbox.gocardless.com/oauth/authorize",
        token_uri="https://connect-sandbox.gocardless.com/oauth/access_token",
        initial_view="signup",
    )
    access_token = flow.step2_exchange(request.args.get("code"))

    jamla["payment_providers"]["gocardless"][
        "access_token"] = access_token.access_token
    fp = open(current_app.config["JAMLA_PATH"], "w")
    # Overwrite jamla file with gocardless access_token
    yaml.safe_dump(jamla, fp, default_flow_style=False)
    # Set users current session to store access_token for instant access
    session["gocardless_access_token"] = access_token.access_token
    session["gocardless_organisation_id"] = access_token.token_response[
        "organisation_id"]

    return redirect(url_for("admin.dashboard"))
示例#7
0
def connect_gocardless_manually():
    form = GocardlessConnectForm()
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    if jamlaApp.has_connected("gocardless"):
        gocardless_connected = True
    else:
        gocardless_connected = False
    if form.validate_on_submit():
        access_token = form.data["access_token"]
        jamla["payment_providers"]["gocardless"]["access_token"] = access_token
        # Check if live or test api key was given
        if "live" in access_token:
            jamla["payment_providers"]["gocardless"]["environment"] = "live"
        else:
            jamla["payment_providers"]["gocardless"]["environment"] = "sandbox"

        fp = open(current_app.config["JAMLA_PATH"], "w")
        # Overwrite jamla file with gocardless access_token
        yaml.safe_dump(jamla, fp, default_flow_style=False)
        # Set users current session to store access_token for instant access
        session["gocardless_access_token"] = access_token
        return redirect(url_for("admin.dashboard"))
    else:
        return render_template(
            "admin/connect_gocardless_manually.html",
            form=form,
            jamla=jamla,
            gocardless_connected=gocardless_connected,
        )
示例#8
0
def get_transactions():
    """Return tuple list of transactions from SSOT"""
    jamla = get_jamla()
    from SSOT import SSOT

    access_token = jamla["payment_providers"]["gocardless"]["access_token"]
    gc_environment = jamla["payment_providers"]["gocardless"]["environment"]
    target_gateways = ({
        "name": "GoCardless",
        "construct": {
            "access_token": access_token,
            "environment": gc_environment
        }
    }, )
    try:
        SSOT = SSOT(target_gateways)
        transactions = SSOT.transactions
    except gocardless_pro.errors.InvalidApiUsageError as e:
        logging.error(e.type)
        logging.error(e.message)
        flash("Invalid GoCardless API token. Correct your GoCardless API key.")
        return redirect(url_for("admin.connect_gocardless_manually"))
    except ValueError as e:
        logging.error(e.message)
        if e.message == "No access_token provided":
            flash("You must connect your GoCardless account first.")
            return redirect(url_for("admin.connect_gocardless_manually"))
        else:
            raise
    return transactions
示例#9
0
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)
示例#10
0
def new_customer():
    jamla = get_jamla()
    package = request.args.get("plan", "not set")
    session["package"] = package
    form = CustomerForm()
    return render_template("new_customer.html",
                           jamla=jamla,
                           form=form,
                           package=package,
                           pages=jamla['pages'])
示例#11
0
def add_jamla_item():
    form = ItemsForm()
    jamla = get_jamla()
    if form.validate_on_submit():
        draftItem = {}
        draftItem["uuid"] = str(uuid.uuid4())
        draftItem["requirements"] = {}
        draftItem["primary_icon"] = {"src": "", "type": ""}
        draftItem["title"] = form.title.data[0].strip()
        draftItem["requirements"]["subscription"] = bool(
            form.subscription.data[0])
        draftItem["requirements"]["note_to_seller_required"] = bool(
            form.note_to_seller_required.data[0])
        draftItem["requirements"]["note_to_buyer_message"] = str(
            form.note_to_buyer_message.data[0])
        try:
            days_before_first_charge = int(
                form.days_before_first_charge.data[0])
        except ValueError:
            days_before_first_charge = 0

        draftItem["days_before_first_charge"] = days_before_first_charge

        if form.monthly_price.data[0] is None:
            draftItem["monthly_price"] = False
        else:
            draftItem["monthly_price"] = float(
                form.monthly_price.data[0]) * 100
        draftItem["requirements"]["instant_payment"] = bool(
            form.instant_payment.data[0])
        if form.sell_price.data[0] is None:
            draftItem["sell_price"] = False
        else:
            draftItem["sell_price"] = float(form.sell_price.data[0]) * 100
        draftItem["selling_points"] = form.selling_points.data[0]
        # Create SKU
        draftItem["sku"] = form.title.data[0].replace(" ", "").strip()
        # Primary icon image storage
        f = form.image.data[0]
        if f:
            images = UploadSet("images", IMAGES)
            filename = images.save(f)
            # symlink to active theme static directory
            img_src = "".join(
                [current_app.config["UPLOADED_IMAGES_DEST"], filename])
            link = "".join([current_app.config["STATIC_FOLDER"], filename])
            os.symlink(img_src, link)
            src = url_for("static", filename=filename)
            draftItem["primary_icon"] = {"src": src, "type": ""}
        jamla["items"].append(draftItem)
        fp = open(current_app.config["JAMLA_PATH"], "w")
        yaml.safe_dump(jamla, fp, default_flow_style=False)
        flash("Item added.")
        return redirect(url_for("admin.dashboard"))
    return render_template("admin/add_jamla_item.html", jamla=jamla, form=form)
示例#12
0
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)
示例#13
0
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"
示例#14
0
def fetch_jamla():
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    # Strip out private values TODO don't store them here, move to .env?
    jamla["payment_providers"] = None
    resp = dict(
        items=jamla["items"],
        company=jamla["company"],
        name="fred",
        email="*****@*****.**",
    )
    return jsonify(resp)
示例#15
0
def order_notes():
    """Notes to seller given during subscription creation"""
    # Migrate dingdb as needed
    dingMigrations = Path(sys.prefix, 'dingdb', 'migrations')
    for migration in dingMigrations.iterdir():
        if migration.is_file():
            subprocess.call("python {} -up -db {}".format(
                migration, current_app.config["DB_FULL_PATH"]),
                            shell=True)

    tdb = dingdb(database=current_app.config["DB_FULL_PATH"])
    orderNotes = tdb.getDingsByType('orderNote')
    jamla = get_jamla()
    return render_template("admin/order-notes.html",
                           jamla=jamla,
                           orderNotes=orderNotes)
示例#16
0
def customers():
    jamla = get_jamla()
    from SSOT import SSOT

    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)

    target_gateways = ()

    if jamlaApp.has_connected("gocardless"):
        access_token = jamla["payment_providers"]["gocardless"]["access_token"]
        gc_environment = jamla["payment_providers"]["gocardless"][
            "environment"]
        target_gateways = target_gateways + ({
            "name": "GoCardless",
            "construct": {
                "access_token": access_token,
                "environment": gc_environment
            }
        }, )

    if jamlaApp.has_connected("stripe"):
        stripe_token = jamla["payment_providers"]["stripe"]["secret_key"]
        target_gateways = target_gateways + ({
            "name": "Stripe",
            "construct": stripe_token
        }, )

    try:
        SSOT = SSOT(target_gateways)
        partners = SSOT.partners
    except gocardless_pro.errors.InvalidApiUsageError as e:
        logging.error(e.type)
        logging.error(e.message)
        flash("Invalid GoCardless API token. Correct your GoCardless API key.")
        return redirect(url_for("admin.connect_gocardless_manually"))
    except ValueError as e:
        logging.error(e.message)
        if e.message == "No access_token provided":
            flash("You must connect your GoCardless account first.")
            return redirect(url_for("admin.connect_gocardless_manually"))
        else:
            raise
    return render_template("admin/customers.html",
                           jamla=jamla,
                           partners=partners)
示例#17
0
def connect_tawk_manually():
    form = TawkConnectForm()
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    if form.validate_on_submit():
        property_id = form.data["property_id"]
        jamla["integrations"]["tawk"]["property_id"] = property_id
        jamla["integrations"]["tawk"]["active"] = True
        # Overwrite jamla file with google tag manager container_id
        fp = open(current_app.config["JAMLA_PATH"], "w")
        yaml.safe_dump(jamla, fp, default_flow_style=False)
        session["tawk_property_id"] = property_id
        return redirect(url_for("admin.dashboard"))
    else:
        return render_template("admin/connect_tawk_manually.html",
                               form=form,
                               jamla=jamla)
示例#18
0
def dashboard():
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)

    if jamlaApp.has_connected("gocardless"):
        gocardless_connected = True
    else:
        gocardless_connected = False
    if jamlaApp.has_connected("stripe"):
        stripe_connected = True
    else:
        stripe_connected = False
    return render_template("admin/dashboard.html",
                           jamla=jamla,
                           gocardless_connected=gocardless_connected,
                           stripe_connected=stripe_connected,
                           loadedModules=getLoadedModules())
示例#19
0
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)
示例#20
0
def generate_login_token():
    form = LoginForm()
    if form.validate_on_submit():
        try:
            send_login_url(form.data["email"])
            jamla = get_jamla()
            source = ' \
                {% extends "admin/layout.html" %} \
                {% block title %} Check your email {% endblock title %} \
                {% block body %} \
                 <div class="container"> \
                  <h1 class="display-2">Great.</h1> \
                  <h2>Now check your email.</h2> \
                  <p class="lead">We\'ve just sent you a login link.</p> \
                 </div> \
                {% endblock body %} '
            return render_template_string(source, jamla=jamla)
        except Exception as e:
            logger.error(e)
            logger.error("Failed to generate login email.")
            return "Failed to generate login email."
示例#21
0
def up_front(sid, package, fname):
    jamla = get_jamla()
    jamlaApp = Jamla()
    jamlaApp.load(jamla=jamla)
    selling_points = jamlaApp.get_selling_points(package)
    upfront_cost = jamlaApp.sku_get_upfront_cost(package)
    monthly_cost = jamlaApp.sku_get_monthly_price(package)
    stripe_pub_key = jamla["payment_providers"]["stripe"]["publishable_key"]
    session["upfront_cost"] = upfront_cost
    session["monthly_cost"] = monthly_cost

    return render_template("up_front_payment.html",
                           jamla=jamla,
                           package=package,
                           fname=fname,
                           selling_points=selling_points,
                           upfront_cost=upfront_cost,
                           monthly_cost=monthly_cost,
                           sid=sid,
                           stripe_pub_key=stripe_pub_key,
                           pages=jamla['pages'])
示例#22
0
def refresh_ssot(resource):
    """Refresh SSOT to fetch newest customers (aka partners) and transactions
  resource is either "customers" or "transactions"
  """
    jamla = get_jamla()
    from SSOT import SSOT

    access_token = jamla["payment_providers"]["gocardless"]["access_token"]
    gc_environment = jamla["payment_providers"]["gocardless"]["environment"]
    target_gateways = ({
        "name": "GoCardless",
        "construct": {
            "access_token": access_token,
            "environment": gc_environment
        }
    }, )
    try:
        SSOT = SSOT(target_gateways, refresh=True)
        partners = SSOT.partners
    except gocardless_pro.errors.InvalidApiUsageError as e:
        logging.error(e.type)
        logging.error(e.message)
        flash("Invalid GoCardless API token. Correct your GoCardless API key.")
        return redirect(url_for("admin.connect_gocardless_manually"))
    except ValueError as e:
        logging.error(e.message)
        if e.message == "No access_token provided":
            flash("You must connect your GoCardless account first.")
            return redirect(url_for("admin.connect_gocardless_manually"))
        else:
            raise
    if resource == "customers":
        flash("Customers refreshed")
        return redirect(url_for('admin.customers'))
    if resource == "transactions":
        flash("Customers refreshed")
        return redirect(url_for('admin.transactions'))
    # Fallback
    flask("Refreshed customers & transactions")
    return redirect(url_for('admin.dashboard'))
示例#23
0
def transactions():
    jamla = get_jamla()
    from SSOT import SSOT

    access_token = jamla["payment_providers"]["gocardless"]["access_token"]
    target_gateways = ({"name": "GoCardless", "construct": access_token}, )
    try:
        SSOT = SSOT(target_gateways)
        transactions = SSOT.transactions
    except gocardless_pro.errors.InvalidApiUsageError as e:
        logging.error(e.type)
        logging(e.message)
        flash("Invalid GoCardless API token. Correct your GoCardless API key.")
        return redirect(url_for("admin.connect_gocardless_manually"))
    except ValueError as e:
        logging.error(e.message)
        if e.message == "No access_token provided":
            flash("You must connect your GoCardless account first.")
            return redirect(url_for("admin.connect_gocardless_manually"))
        else:
            raise
    return render_template("admin/transactions.html",
                           jamla=jamla,
                           transactions=transactions)
示例#24
0
def store_customer():
    form = CustomerForm()
    if form.validate():
        given_name = form.data["given_name"]
        family_name = form.data["family_name"]
        address_line_one = form.data["address_line_one"]
        city = form.data["city"]
        postcode = form.data["postcode"]
        email = form.data["email"]
        mobile = form.data["mobile"]
        now = datetime.datetime.now()
        # Store customer in session
        sid = session["sid"]
        # Store email in session
        session["email"] = email

        # Store plan in session
        jamlaApp = Jamla()
        jamla = get_jamla()
        jamlaApp.load(jamla=jamla)
        if jamlaApp.sku_exists(request.args.get("plan")):
            wants = request.args.get("plan")
            session["plan"] = wants
        db = get_db()
        db.execute(
            "INSERT INTO person VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            (
                sid,
                now,
                given_name,
                family_name,
                address_line_one,
                city,
                postcode,
                email,
                mobile,
                wants,
                "null",
                "null",
                False,
            ),
        )
        db.commit()
        # Store note to seller in session if there is one
        note_to_seller = form.data["note_to_seller"]
        session["note_to_seller"] = note_to_seller
        if jamlaApp.requires_instantpayment(session["package"]):
            return redirect(
                url_for(
                    "views.up_front",
                    _scheme="https",
                    _external=True,
                    sid=sid,
                    package=wants,
                    fname=given_name,
                ))
        if jamlaApp.requires_subscription(session["package"]):
            # Check if in iframe
            if form.data["is_iframe"] == "True":
                insideIframe = True
            else:
                insideIframe = False
            return redirect(
                url_for("views.establish_mandate", inside_iframe=insideIframe))
        return redirect(
            url_for("views.thankyou", _scheme="https", _external=True))
    else:
        return "Oops, there was an error processing that form, please go back and try again."
示例#25
0
def delete_jamla_item():
    jamla = get_jamla()
    # Filter archived items
    jamlaApp = Jamla()
    jamla = jamlaApp.filter_archived_items(jamla)
    return render_template("admin/delete_jamla_item_choose.html", jamla=jamla)
示例#26
0
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"])
示例#27
0
def index():
    jamla = get_jamla()
    return render_template("index.html", jamla=jamla)
示例#28
0
def login():
    jamla = get_jamla()
    form = LoginForm()
    return render_template("/admin/login.html", form=form, jamla=jamla)
示例#29
0
def edit_jamla():
    """Update jamla items
    
    Note sku items are immutable, when a change is made to an item, its old
    item is archived and a new sku item is created with a new uuid. This is to
    protect data integriry and make sure plan history is retained, via its uuid.
    If a user needs to change a subscription, they should change to a different
    plan with a different uuid.

    """

    form = ItemsForm()
    jamla = get_jamla()
    # Filter archived items
    jamlaApp = Jamla()
    jamla = jamlaApp.filter_archived_items(jamla)
    if form.validate_on_submit():
        jamla["company"]["name"] = request.form["company_name"]
        jamla["company"]["slogan"] = request.form["slogan"]
        jamla["users"][0] = request.form["email"]
        # Loop items
        for index in request.form.getlist("itemIndex", type=int):

            # Archive existing item then create new sku item
            # (remember, edit edits create new items because
            # skus are immutable)

            jamla["items"][index]["archived"] = True  # Archive item

            # Build new sku
            draftItem = {}
            draftItem["uuid"] = str(uuid.uuid4())
            draftItem["requirements"] = {}
            # Preserve primary icon if exists
            draftItem["primary_icon"] = jamla["items"][index]["primary_icon"]

            draftItem["title"] = getItem(form.title.data, index,
                                         default="").strip()

            draftItem["sku"] = draftItem["title"].replace(" ", "").strip()

            draftItem["requirements"]["subscription"] = bool(
                getItem(form.subscription.data, index))
            if getItem(form.monthly_price.data, index, default=0) is None:
                monthly_price = 0.00
            else:
                monthly_price = getItem(
                    form.monthly_price.data, index, default=0) * 100
            draftItem["monthly_price"] = monthly_price

            draftItem["requirements"]["instant_payment"] = bool(
                getItem(form.instant_payment.data, index))
            draftItem["requirements"]["note_to_seller_required"] = bool(
                getItem(form.note_to_seller_required.data, index))

            draftItem["requirements"]["note_to_buyer_message"] = str(
                getItem(form.note_to_buyer_message, index, default="").data)

            try:
                days_before_first_charge = int(
                    form.days_before_first_charge[index].data)
            except ValueError:
                days_before_first_charge = 0

            draftItem["days_before_first_charge"] = days_before_first_charge

            if getItem(form.sell_price.data, index, default=0) is None:
                sell_price = 0.00
            else:
                sell_price = getItem(form.sell_price.data, index,
                                     default=0) * 100
            draftItem["sell_price"] = sell_price

            draftItem["selling_points"] = getItem(form.selling_points.data,
                                                  index,
                                                  default="")
            # Primary icon image storage
            f = getItem(form.image.data, index)
            if f:
                images = UploadSet("images", IMAGES)
                filename = images.save(f)
                # symlink to active theme static directory
                img_src = "".join(
                    [current_app.config["UPLOADED_IMAGES_DEST"], filename])
                link = "".join([current_app.config["STATIC_FOLDER"], filename])
                symlink(img_src, link, overwrite=True)
                src = url_for("static", filename=filename)
                draftItem["primary_icon"] = {"src": src, "type": ""}
            # Add new sku to items
            jamla["items"].append(draftItem)
            fp = open(current_app.config["JAMLA_PATH"], "w")
            yaml.safe_dump(jamla, fp, default_flow_style=False)
        flash("Item(s) updated.")
        # Trigger a reload by touching the wsgi file.
        # Which file we need to touch depends on the wsgi config
        # e.g. on uwsgi to set it to subscribie.wsgi on uwsgi we pass:
        # uwsgi --http :9090 --workers 2 --wsgi-file subscribie.wsgi \
        #  --touch-chain-reload subscribie.wsgi
        # To uwsgi. The `--touch-chain-reload` option tells uwsgi to perform
        # a graceful reload. "When triggered, it will restart one worker at
        # time, and the following worker is not reloaded until the previous one
        # is ready to accept new requests. We must use more than one worker for
        # this to work. See:
        # https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#chain-reloading-lazy-apps
        wsgiFile = os.path.abspath(''.join([os.getcwd(), '/subscribie.wsgi']))
        p = Path(wsgiFile)
        p.touch(exist_ok=True)  # Triggers the graceful reload
        return redirect(url_for("admin.dashboard"))
    return render_template("admin/edit_jamla.html", jamla=jamla, form=form)