Exemplo n.º 1
0
def member_customer_portal(account: Account, base_url: str):
    """
    Access stripe customer portal
    :param account:
    :param base_url:
    :return: customer portalUrl
    """
    stripe_customer_id = get_stripe_customer(account)

    if stripe_customer_id is None:
        raise P2k16UserException(
            'No billing information available. Create a subscription first.')

    return_url = base_url + '/#!/'

    try:
        session = stripe.billing_portal.Session.create(
            customer=stripe_customer_id, return_url=return_url)

        return {'portalUrl': session.url}

    except stripe.error.StripeError as e:
        logger.error("Stripe error: " + repr(e.json_body))

        raise P2k16UserException(
            "Stripe error. Contact [email protected] if the "
            "problem persists.")
Exemplo n.º 2
0
def member_create_checkout_session(account: Account, base_url: str,
                                   price_id: int):
    """
    Create a new subscription using Stripe Checkout / Billing
    :param account:
    :param base_url:
    :param price_id:
    :return: checkout sessionId
    """
    stripe_customer_id = get_stripe_customer(account)

    # Existing customers should only use this flow if they have no subscriptions.
    if stripe_customer_id is not None:
        # Get customer object
        cu = stripe.Customer.retrieve(stripe_customer_id.stripe_id,
                                      expand=['subscriptions'])

        if len(cu.subscriptions.data) > 0:
            raise P2k16UserException("User is already subscribed.")

    else:
        # Create a new customer object
        stripe_customer_id = stripe.Customer.create(name=account.name,
                                                    email=account.email)

        # Store stripe customer in case checkout fails.
        stripe_customer = StripeCustomer(stripe_customer_id.id)
        db.session.add(stripe_customer)
        db.session.commit()

    success_url = base_url + '/#!/?session_id={CHECKOUT_SESSION_ID}'
    cancel_url = base_url + '/#!/'

    try:
        checkout_session = stripe.checkout.Session.create(
            success_url=success_url,
            cancel_url=cancel_url,
            payment_method_types=["card"],
            mode="subscription",
            line_items=[{
                "price": price_id,
                "quantity": 1
            }],
            metadata={"accountId": account.id},
            customer=stripe_customer_id,
        )

        session_id = checkout_session['id']

        return {'sessionId': session_id}

    except stripe.error.StripeError as e:
        logger.error("Stripe error: " + repr(e.json_body))

        raise P2k16UserException(
            "Stripe error. Contact [email protected] if the problem persists."
        )
Exemplo n.º 3
0
def _assert_can_admin_circle(admin: Account, circle: Circle):
    if can_admin_circle(admin, circle):
        return

    if circle.management_style == CircleManagementStyle.ADMIN_CIRCLE:
        raise P2k16UserException(
            "{} is not in the admin circle ({}) for circle {}".format(
                admin.username, circle.admin_circle.name, circle.name))
    elif circle.management_style == CircleManagementStyle.SELF_ADMIN:
        raise P2k16UserException("{} is not an admin of {}".format(
            admin.username, circle.name))
Exemplo n.º 4
0
def _check_is_circle_admin(circle: Circle, admin: Account):
    admin_circle = Circle.find_by_name(circle.name + '-admin')

    if admin_circle is None:
        raise P2k16UserException(
            'There is no admin circle (%s-admin") for circle "%s"'.format(
                circle.name, circle.name))

    if not is_account_in_circle(admin, admin_circle):
        raise P2k16UserException('Account %s is not an administrator of %s' %
                                 (admin.username, circle.description))
Exemplo n.º 5
0
def register_account(username: str, email: str, name: str, password: str,
                     phone: str) -> Account:
    account = Account.find_account_by_username(username)
    if account:
        raise P2k16UserException("Username is taken")

    account = Account.find_account_by_email(email)
    if account:
        raise P2k16UserException("Email is already registered")

    account = Account(username, email, name, phone, password)
    db.session.add(account)
    return account
Exemplo n.º 6
0
    def open_doors(self, account: Account, doors: List[Door]):
        door_circle = Circle.get_by_name('door')

        can_open_door = False

        if account_management.is_account_in_circle(
                account,
                door_circle) and membership_management.active_member(account):
            can_open_door = True

        if len(Company.find_active_companies_with_account(account.id)) > 0:
            can_open_door = True

        if not can_open_door:
            # Only non-office users may fail here
            if not membership_management.active_member(account):
                raise P2k16UserException(
                    '{} does not have an active membership'.format(
                        account.display_name()))

            if not account_management.is_account_in_circle(
                    account, door_circle):
                raise P2k16UserException('{} is not in the door circle'.format(
                    account.display_name()))

        publishes = []

        if not event_management.has_opened_door(account):
            system = Account.find_account_by_username("system")
            logger.info("First door opening for {}".format(account))
            badge_management.create_badge(account, system,
                                          "first-door-opening")

        for door in doors:
            logger.info(
                'Opening door. username={}, door={}, open_time={}'.format(
                    account.username, door.key, door.open_time))
            event_management.save_event(OpenDoorEvent(door.key))
            publishes.append((self.prefix + door.topic, str(door.open_time)))

        # Make sure everything has been written to the database before actually opening the door.
        db.session.flush()

        # TODO: move this to a handler that runs after the transaction is done
        # TODO: we can look at the responses and see if they where successfully sent/received.
        for topic, open_time in publishes:
            logger.info("Sending message: {}: {}".format(topic, open_time))
            self._client.publish(topic, open_time)
Exemplo n.º 7
0
    def open_doors(self, account: Account, doors: List[Door]):

        can_open_door = authz_management.can_haz_door_access(account)

        if not can_open_door:
            raise P2k16UserException(
                '{} does not have an active membership, or lack door circle membership'
                .format(account.display_name()))

        publishes = []

        if not event_management.has_opened_door(account):
            system = Account.find_account_by_username("system")
            logger.info("First door opening for {}".format(account))
            badge_management.create_badge(account, system,
                                          "first-door-opening")

        for door in doors:
            logger.info(
                'Opening door. username={}, door={}, open_time={}'.format(
                    account.username, door.key, door.open_time))
            event_management.save_event(OpenDoorEvent(door.key))
            publishes.append((self.prefix + door.topic, str(door.open_time)))

        # Make sure everything has been written to the database before actually opening the door.
        db.session.flush()

        # TODO: move this to a handler that runs after the transaction is done
        # TODO: we can look at the responses and see if they where successfully sent/received.
        for topic, open_time in publishes:
            logger.info("Sending message: {}: {}".format(topic, open_time))
            self._client.publish(topic, open_time)
Exemplo n.º 8
0
def _data_tool_save():
    circle_name = request.json["circle"]
    circle = Circle.find_by_name(circle_name)

    if not circle:
        raise P2k16UserException("No such circle: {}".format(circle_name))

    _id = request.json.get("id", None)

    if _id:
        tool = ToolDescription.find_by_id(_id)

        if tool is None:
            abort(404)

        logger.info("Updating tool: {}".format(tool))
        tool.name = request.json["name"]
        tool.circle = circle
        tool.description = request.json["description"]
    else:
        logger.info("Creating new tooldescription: {}".format(
            request.json["name"]))
        tool = ToolDescription(request.json["name"],
                               request.json["description"], circle)

    db.session.add(tool)
    db.session.commit()
    db.session.flush()
    logger.info("Update tool: {}".format(tool.name))

    return jsonify(tool_to_json(tool))
Exemplo n.º 9
0
def _data_company_save():
    contact_id = request.json["contact"]
    contact = Account.find_account_by_id(contact_id)
    if not contact:
        raise P2k16UserException("No such account: {}".format(contact_id))

    _id = request.json.get("id", None)

    if _id:
        company = Company.find_by_id(_id)

        if company is None:
            abort(404)

        logger.info("Updating company: {}".format(company))
        company.name = request.json["name"]
        company.contact_id = contact.id
        company.active = request.json["active"]
    else:
        name = request.json["name"]
        active = request.json["active"]
        logger.info("Registering new company: {}".format(name))
        company = Company(name, contact, active)

    db.session.add(company)
    db.session.commit()

    return jsonify(company_to_json(company, include_employees=True))
Exemplo n.º 10
0
Arquivo: door.py Projeto: bitraf/p2k16
    def open_doors(self, account: Account, doors):
        can_open_door = authz_management.can_haz_door_access(account, doors)
        if not can_open_door:
            f = "{} does not have an active membership, or lacks door circle membership"
            raise P2k16UserException(f.format(account.display_name()))

        if not event_management.has_opened_door(account):
            system = Account.find_account_by_username("system")
            logger.info("First door opening for {}".format(account))
            badge_management.create_badge(account, system,
                                          "first-door-opening")

        for door in doors:
            lf = "Opening door. username={}, door={}, open_time={}"
            logger.info(lf.format(account.username, door.key, door.open_time))

            event_management.save_event(OpenDoorEvent(door.key))

        # Make sure everything has been written to the database before actually opening the door.
        db.session.flush()

        # TODO: move this to a handler that runs after the transaction is done
        # TODO: we can look at the responses and see if they where successfully sent/received.
        for door in doors:
            if isinstance(door, DlockDoor):
                self.dlock.open(door)
            elif isinstance(door, MqttDoor):
                self.mqtt.open(door)
            else:
                P2k16TechnicalException("Unknown kind of door")
Exemplo n.º 11
0
def member_get_details(account):
    # Get mapping from account to stripe_id
    stripe_customer_id = get_stripe_customer(account)

    details = {}

    details['stripe_pubkey'] = os.environ.get('STRIPE_PUBLIC_KEY')

    try:
        # Get payment details
        details['card'] = "N / A"
        details['card_exp'] = ""
        details['stripe_price'] = "0"
        details['stripe_subscription_status'] = "none"

        if stripe_customer_id is not None:
            # Get customer object
            cu = stripe.Customer.retrieve(stripe_customer_id.stripe_id)

            if len(cu.sources.data) > 0:
                card = cu.sources.data[0]
                details['card'] = "**** **** **** " + card.last4
                details['card_exp'] = "%r/%r" % (card.exp_month, card.exp_year)

            # Get stripe subscription to make sure it matches local database
            assert len(cu.subscriptions.data) <= 1
            for sub in cu.subscriptions.data:
                details['stripe_subscription_status'] = sub.status
                details['stripe_price'] = sub.plan.amount / 100

        # Get current membership
        membership = get_membership(account)
        if membership is not None:
            details['fee'] = membership.fee
            details['first_membership'] = membership.first_membership
            details['start_membership'] = membership.start_membership
        else:
            details['fee'] = 0

        # Export payments
        payments = []
        for pay in get_membetship_payments(account):
            payments.append({
                'id': pay.id,
                'start_date': pay.start_date,
                'end_date': pay.end_date,
                'amount': float(pay.amount),
                'payment_date': pay.payment_date
            })

        details['payments'] = payments

    except stripe.error.StripeError as e:
        raise P2k16UserException(
            "Error reading data from Stripe. Contact [email protected] if the problem persists."
        )

    return details
Exemplo n.º 12
0
    def checkout_tool(self, account: Account, tool: ToolDescription):
        # Check that user has correct circle and is paying member
        if not account_management.is_account_in_circle(account, tool.circle):
            raise P2k16UserException('{} is not in the {} circle'.format(
                account.display_name(), tool.circle.name))

        if not membership_management.active_member(account) \
                and len(Company.find_active_companies_with_account(account.id)) == 0:
            raise P2k16UserException(
                '{} does not have an active membership and is not employed in an active company'
                .format(account.display_name()))

        logger.info('Checking out tool. username={}, tool={}'.format(
            account.username, tool.name))

        # Verify that tool is not checked out by someone else. Check in first if it is.
        checkout = ToolCheckout.find_by_tool(tool)
        if checkout:
            if checkout.account is account:
                raise P2k16UserException('Tools can only be checked out once.')

            logger.info(
                'Tool checked out by someone else. Assuming control: username={}, tool={}, old_username={}'
                .format(account.username, tool.name, checkout.account.name))
            self.checkin_tool(checkout.account, checkout.tool_description)

        # Make a new checkout reservation
        event_management.save_event(
            ToolCheckoutEvent(tool.name, datetime.now(), account))
        checkout = ToolCheckout(tool, account, datetime.now())
        db.session.add(checkout)

        # Make sure everything has been written to the database before actually opening the door.
        db.session.flush()

        # TODO: move this to a handler that runs after the transaction is done
        # TODO: we can look at the responses and see if they where successfully sent/received.
        #        for topic, open_time in publishes:
        #            logger.info("Sending message: {}: {}".format(topic, open_time))
        #            self._client.publish(topic, open_time)

        topic = self._mqtt_topic(tool=tool.name, action='unlock')
        payload = 'true'
        logger.info("Sending message: {}: {}".format(topic, payload))
        self._client.publish(topic, payload)
Exemplo n.º 13
0
def _load_circle_admin(account_id, circle_id, admin_id):
    account = Account.find_account_by_id(account_id)
    admin = Account.find_account_by_id(admin_id)
    circle = Circle.find_by_id(circle_id)

    if account is None or admin is None or circle is None:
        raise P2k16UserException('Bad values')

    return account, admin, circle
Exemplo n.º 14
0
    def add_member(self, account: Account, comment: Optional[str]):
        if comment:
            comment = comment.strip()

        if self.comment_required_for_membership and len(comment) == 0:
            raise P2k16UserException(
                "This circle requires memberships to have a comment")

        self.members.append(CircleMember(self, account, comment))
Exemplo n.º 15
0
def service_authz_login():
    username = request.json["username"]
    account = Account.find_account_by_username(username)
    password = request.json["password"]

    if not account:
        logger.info("Login: Bad login attempt, no such user: {}".format(username))
        raise P2k16UserException("Invalid credentials")
    if not account.valid_password(password):
        logger.info("Login: Bad login attempt, wrong password: {}".format(username))
        raise P2k16UserException("Invalid credentials")
    circles = account_management.get_circles_for_account(account.id)
    badges = badge_management.badges_for_account(account.id)

    logger.info("Login: username={}, circles={}".format(username, circles))

    authenticated_account = auth.AuthenticatedAccount(account, circles)
    flask_login.login_user(authenticated_account)

    return jsonify(account_to_json(account, circles, badges))
Exemplo n.º 16
0
def remove_account_from_circle(account: Account, circle: Circle,
                               admin: Account):
    logger.info("Removing %s from circle %s, admin=%s" %
                (account.username, circle.name, admin.username))

    _assert_can_admin_circle(admin, circle)

    if not is_account_in_circle(account, circle):
        raise P2k16UserException(
            "Account isn't a member of the circle, cannot be removed")

    circle.remove_member(account)
Exemplo n.º 17
0
def add_account_to_circle(account: Account, circle: Circle, admin: Account,
                          comment: str):
    logger.info("Adding %s to circle %s, admin=%s" %
                (account.username, circle.name, admin.username))

    _assert_can_admin_circle(admin, circle)

    if is_account_in_circle(account, circle):
        raise P2k16UserException(
            "Account is already a member of the cirlce, cannot be added again")

    circle.add_member(account, comment)
Exemplo n.º 18
0
def create_circle(name: str,
                  description: str,
                  comment_required_for_membership,
                  management_style: CircleManagementStyle,
                  admin_circle_name: Optional[str] = None,
                  username: Optional[str] = None,
                  comment: Optional[str] = None) -> Circle:
    c = Circle(name, description, comment_required_for_membership,
               management_style)

    if management_style == CircleManagementStyle.ADMIN_CIRCLE:
        if admin_circle_name is None:
            raise P2k16UserException(
                "An admin circle is required when management style is set to ADMIN_CIRCLE"
            )

        admin_circle = Circle.find_by_name(admin_circle_name)

        if admin_circle is None:
            raise P2k16UserException(
                "No such circle: {}".format(admin_circle_name))

        c.admin_circle = admin_circle

    elif management_style == CircleManagementStyle.SELF_ADMIN:
        if username is None:
            raise P2k16UserException(
                "An initial member's username is required when management style is set to "
                "SELF_ADMIN")

        account = Account.find_account_by_username(username)

        if account is None:
            raise P2k16UserException("No such account: {}".format(username))

        c.add_member(account, comment or "")

    db.session.add(c)

    return c
Exemplo n.º 19
0
def service_set_password():
    old_password = flask.request.json["oldPassword"]
    new_password = flask.request.json["newPassword"]

    a = flask_login.current_user.account # type: Account

    if not a.valid_password(old_password):
        raise P2k16UserException("Bad password")
    else:
        account_management.set_password(a, new_password, old_password=old_password)
        db.session.commit()

    return jsonify({})
Exemplo n.º 20
0
def remove_circle(admin: Account, circle: Circle):
    _assert_can_admin_circle(admin, circle)

    logger.info("Removing circle, id={}, admin={}".format(circle.id, admin.id))
    c = Circle.get_by_id(circle.id)

    if c.management_style == CircleManagementStyle.SELF_ADMIN:
        ok = len(c.members) == 1 and c.members[0].account == admin

        if not ok:
            raise P2k16UserException(
                "A circle which is self-administrated must only contain the remover."
            )

    elif c.management_style == CircleManagementStyle.ADMIN_CIRCLE:
        if len(c.members) != 0:
            raise P2k16UserException(
                "The circle has to be empty to be removed.")
    else:
        raise P2k16UserException("Unknown management style")

    Circle.delete_by_id(circle.id)
Exemplo n.º 21
0
def register_account(username: str, email: str, name: str, password: str,
                     phone: str) -> Account:
    account = Account.find_account_by_username(username)
    if account:
        raise P2k16UserException("Username is taken")

    account = Account.find_account_by_email(email)
    if account:
        raise P2k16UserException("Email is already registered")

    if name is None:
        raise P2k16UserException("Name cannot be empty.")

    if " " in username:
        raise P2k16UserException("Username cannot contain spaces")

    if not re.match(r"^[a-zA-Z0-9@._+-]+", username):
        raise P2k16UserException(
            "Username can only contain a-z, 0-9, @, ., _, + and -.")

    account = Account(username, email, name, phone, password)
    db.session.add(account)
    return account
Exemplo n.º 22
0
def open_door():
    a = flask_login.current_user.account

    dc = flask.current_app.config.door_client  # type: DoorClient

    doors = []

    for key in request.json["doors"]:
        if key in p2k16.core.door.doors:
            doors.append(p2k16.core.door.doors[key])
        else:
            raise P2k16UserException("Unknown door: {}".format(key))

    dc.open_doors(a, doors)
    db.session.commit()
    return jsonify(dict())
Exemplo n.º 23
0
def member_cancel_membership(account):
    try:
        # Update local db
        membership = get_membership(account)
        db.session.delete(membership)

        # Update stripe
        stripe_customer_id = get_stripe_customer(account)

        for sub in stripe.Subscription.list(customer=stripe_customer_id):
            sub.delete(at_period_end=True)

        db.session.commit()

    except stripe.error.StripeError as e:
        logger.error("Stripe error: " + repr(e.json_body))

        raise P2k16UserException(
            "Stripe error. Contact [email protected] if the problem persists."
        )
Exemplo n.º 24
0
def create():
    account = flask_login.current_user.account  # type: Account

    title = request.json["title"]
    recipient_username = request.json.get("recipient", None)

    if recipient_username:
        recipient = Account.find_account_by_username(recipient_username)

        if not recipient:
            raise P2k16UserException(
                "No such username: {}".format(recipient_username))
    else:
        recipient = account

    badge_management.create_badge(recipient, account, title)

    circles = account_management.get_circles_for_account(account.id)
    badges = badge_management.badges_for_account(account.id)

    db.session.commit()

    return jsonify(account_to_json(account, circles, badges))
Exemplo n.º 25
0
def create_badge(receiver: Account, awarder: Account, title: str) -> AccountBadge:
    desc = _load_description(title)

    logger.info("Creating badge: title={}, receiver={}, awarder={}".format(title, receiver.username, awarder.username))
    if desc:
        logger.info("desc.certification_circle={}".format(desc.certification_circle))

    if desc:
        if desc.certification_circle:
            if not account_management.is_account_in_circle(awarder, desc.certification_circle):
                raise P2k16UserException("The awarder {} is not a valid certifier".format(awarder.username))
    else:
        desc = BadgeDescription(title)
        db.session.add(desc)
        db.session.flush([desc])

    ab = AccountBadge(receiver, awarder, desc)
    db.session.add(ab)
    db.session.flush()

    event_management.save_event(BadgeAwardedEvent(ab, desc))

    return ab
Exemplo n.º 26
0
 def wrapper(*args, **kw):
     try:
         js.validate(flask.request.json, schema)
         return f(*args, **kw)
     except js.ValidationError as e:
         raise P2k16UserException(e.message)
Exemplo n.º 27
0
def member_set_membership(account, membership_plan, membership_price):
    # TODO: Remove membership_price and look up price from model

    try:
        membership = get_membership(account)

        if membership_plan == 'none':
            member_cancel_membership(account)
            return True

        # --- Update membership in local db ---
        if membership is not None:
            if membership.fee is membership_price:
                # Nothing's changed.
                logger.info(
                    "No membership change for user=%r, type=%r, amount=%r" %
                    (account.username, membership_plan, membership_price))
                return
            else:
                membership.fee = membership_price
                membership.start_membership = datetime.now()
        else:
            # New membership
            membership = Membership(membership_price)

        # --- Update membership in stripe ---

        # Get customer object
        stripe_customer_id = get_stripe_customer(account)

        if stripe_customer_id is None:
            raise P2k16UserException(
                "You must set a credit card before changing plan.")

        # Check for active subscription
        subscriptions = stripe.Subscription.list(customer=stripe_customer_id)

        if subscriptions is None or len(subscriptions) == 0:
            sub = stripe.Subscription.create(customer=stripe_customer_id,
                                             items=[{
                                                 "plan": membership_plan
                                             }])
        else:
            sub = next(iter(subscriptions), None)
            stripe.Subscription.modify(sub.id,
                                       cancel_at_period_end=False,
                                       items=[{
                                           'id': sub['items']['data'][0].id,
                                           'plan': membership_plan
                                       }],
                                       prorate=False)

        # Commit to db
        db.session.add(membership)
        db.session.commit()

        logger.info(
            "Successfully updated membership type for user=%r, type=%r, amount=%r"
            % (account.username, membership_plan, membership_price))

        mail.send_new_member(account)

        return True

    except stripe.error.CardError as e:
        err = e.json_body.get('error', {})
        msg = err.get('message')

        logger.info("Card processing failed for user=%r, error=%r" %
                    (account.username, err))

        raise P2k16UserException("Error charging credit card: %r" % msg)

    except stripe.error.StripeError as e:
        logger.error("Stripe error: " + repr(e.json_body))

        raise P2k16UserException(
            "Stripe error. Contact [email protected] if the problem persists."
        )
Exemplo n.º 28
0
def member_set_credit_card(account, stripe_token):
    # Get mapping from account to stripe_id
    stripe_customer_id = get_stripe_customer(account)

    try:
        if stripe_customer_id is None:
            # Create a new stripe customer and set source
            cu = stripe.Customer.create(description="Customer for %r" %
                                        account.name,
                                        email=account.email,
                                        source=stripe_token)
            stripe_customer_id = StripeCustomer(cu.stripe_id)

            logger.info("Created customer for user=%r" % account.username)
        else:
            # Get customer object
            cu = stripe.Customer.retrieve(stripe_customer_id.stripe_id)

            if cu is None or (hasattr(cu, 'deleted') and cu.deleted):
                logger.error(
                    "Stripe customer does not exist. This should not happen! account=%r, stripe_id=%r"
                    % (account.username, stripe_token))
                raise P2k16UserException(
                    "Set credit card invalid state. Contact [email protected]"
                )

            # Create a new default card
            new_card = cu.sources.create(source=stripe_token)
            cu.default_source = new_card.id
            cu.save()

            # Delete any old cards
            for card in cu.sources.list():
                if card.id != new_card.id:
                    card.delete()

        # Commit to db
        db.session.add(stripe_customer_id)
        db.session.commit()

        # Check if there are any outstanding invoices on this account that needs billing
        for invoice in stripe.Invoice.list(customer=cu.stripe_id):
            if invoice.paid is False and invoice.closed is False and invoice.forgiven is False:
                invoice.pay()

        logger.info("Successfully updated credit card for user=%r" %
                    account.username)
        return True

    except stripe.error.CardError as e:
        err = e.json_body.get('error', {})
        msg = err.get('message')

        logger.info("Card processing failed for user=%r, error=%r" %
                    (account.username, err))

        raise P2k16UserException("Error updating credit card: %r" % msg)

    except stripe.error.StripeError as e:
        logger.error("Stripe error: " + repr(e.json_body))

        raise P2k16UserException(
            "Error updating credit card due to stripe error. Contact [email protected] if the "
            "problem persists.")
Exemplo n.º 29
0
 def on_before_update(self):
     if self.management_style == CircleManagementStyle.SELF_ADMIN and len(
             self.members) == 0:
         raise P2k16UserException(
             "A circle which is self-administrated must have at least one member"
         )
Exemplo n.º 30
0
def member_set_membership(account, membership_plan, membership_price):
    # TODO: Remove membership_price and look up price from model

    try:
        membership = get_membership(account)

        if membership_plan == 'none':
            member_cancel_membership(account)
            return True

        # --- Update membership in local db ---
        if membership is not None:
            if membership.fee is membership_price:
                # Nothing's changed.
                logger.info(
                    "No membership change for user=%r, type=%r, amount=%r" %
                    (account.username, membership_plan, membership_price))
                return
            else:
                membership.fee = membership_price
                membership.start_membership = datetime.now()
        else:
            # New membership
            membership = Membership(membership_price)

        # --- Update membership in stripe ---

        # Get customer object
        stripe_customer_id = get_stripe_customer(account)

        new_sub = stripe.Subscription.create(customer=stripe_customer_id,
                                             items=[{
                                                 "plan": membership_plan
                                             }])

        # Remove existing subscriptions
        for sub in stripe.Subscription.list(customer=stripe_customer_id):
            if new_sub.id != sub.id:
                sub.delete(at_period_end=False)

        # Commit to db
        db.session.add(membership)
        db.session.commit()

        logger.info(
            "Successfully updated membership type for user=%r, type=%r, amount=%r"
            % (account.username, membership_plan, membership_price))
        return True

    except stripe.error.CardError as e:
        err = e.json_body.get('error', {})
        msg = err.get('message')

        logger.info("Card processing failed for user=%r, error=%r" %
                    (account.username, err))

        raise P2k16UserException("Error charging credit card: %r" % msg)

    except stripe.error.StripeError as e:
        logger.error("Stripe error: " + repr(e.json_body))

        raise P2k16UserException(
            "Stripe error. Contact [email protected] if the problem persists."
        )