def _assert_no_duplicate_submerchant(self, user_id):
        """
        Handles asserting that a user doesn't already have a submerchant.

        :param str user_id: The user's UUID
        :raises: FacadeException
        """
        try:
            UserDAO().get(user_id)
        except DAOException as e:
            logging.warning(
                'Requested user {0} does not exist with exception: {1}'.format(
                    user_id,
                    e,
                ))
            raise FacadeException('Requested user does not exist.')

        merchant_dao = MerchantDAO()
        found_submerchant = merchant_dao.get_submerchant_by_id(user_id)
        if found_submerchant is not None:
            logging.warning(
                'Attempted duplicate submerchant for user: {0}'.format(
                    user_id, ))
            raise FacadeException(
                'You already have a submerchant account created.')
    def regenerate_reset_password_token(self, email):
        """
        Regenerates a reset password token and sends another email.

        :param str email: The email of the user who forgot/lost their
        reset password email token.
        :rtype: str
        :return: The newly generated token.
        """
        try:
            new_token, user = UserDAO().regenerate_token(email, 'reset_token')

            MailQueueDAO().push_to_queue(
                '*****@*****.**', user.email, 'Please verify your account',
                """
                Your new account at Kronikl.io is now available. Please go to
                <a href="http://{0}/#/reset_password/{1}">Reset my Password</a>
                to activate your account.
                """.format(
                    'localhost:8080' if current_app.config['ENVIRONMENT']
                    == 'Dev' else 'app.kronikl.io', new_token))

            return new_token
        except DAOException as e:
            logging.error(
                'Failed to regenerate reset token with exception: {0}'.format(
                    e))

            raise FacadeException('Failed to regenerate reset token.',
                                  e.status_code)
Esempio n. 3
0
    def create_new_event(
        self,
        scheduling_user_id,
        scheduled_user_id,
        localized_start_time,
        localized_end_time,
        local_tz,
        notes,
        nonce,
        address_id=None,
    ):
        """
        Handles creation of a new event and payment processing.

        :param str scheduling_user_id: The user who is booking another's time
        :param str scheduled_user_id: Their time is being booked.
        :param datetime.datetime localized_start_time: Localized start
        :param datetime.datetime localized_end_time: The localized end
        :param str local_tz: The timezone which this was booked in.
        :param str notes: Any additional notes to add onto the event.
        :param str nonce: The nonce which determines the payment method
        being used.
        :param str address_id: An address to be used whenever billing. If not
        provided, then we attempt to find a default address.
        :rtype: EventTable
        :return: The newly created event.
        """
        if address_id is None:
            address = AddressDAO().get_default_for_user(scheduling_user_id)
        else:
            address = AddressDAO().get_by_public_id(address_id,
                                                    scheduling_user_id)

        try:
            new_event = EventDAO().create_new_event(scheduling_user_id,
                                                    scheduled_user_id,
                                                    localized_start_time,
                                                    localized_end_time,
                                                    local_tz,
                                                    notes,
                                                    skip_commit=True)

            BraintreePaymentFacade().issue_new_payment(new_event, nonce,
                                                       address)
        except IntegrationException as e:
            db.session.rollback()
            logging.error('Failed to create new transaction with exc of {0}.'
                          'Rolling back event creation for event {1}'.format(
                              e, new_event.public_id))
            raise FacadeException('Failed to finish sale.')
        except DAOException as e:
            raise e

        return new_event
    def create_new_subscription(self, user_id, *,
                                skip_commit=False, plan_id='Basic0x01'):
        """
        Handles creating a new subscription for an existing customer account.

        :param str user_id: The user to create the subscription for.
        :param bool skip_commit: Should we skip committing? Facades on facades
        :param str plan_id: The plan ID. Don't touch!
        :rtype: SubscriptionTable
        :return: The newly created subscription.
        """
        try:
            found_customer = self.customer_dao.get_customer_by_user_id(user_id)

            unique_id = uuid.uuid4()

            new_subscription = self.subscription_integration.start_subscription(
                unique_id,
                found_customer.credit_card_token,
                plan_id,
            )

            self.subscription_dao.create_subscription(
                unique_id,
                user_id,
                skip_commit=skip_commit,
            )

            db.session.commit()

            return new_subscription
        except Exception as e:
            logging.error(
                'Failed to create new subscription for user {0} with '
                'exception {1} for pre-existing customer.'.format(
                    user_id,
                    e,
                )
            )
            db.session.rollback()
            raise FacadeException(
                'Failed to start subscription.'
            )
    def create_submerchant(self,
                           submerchant_info,
                           user_id,
                           *,
                           skip_commit=False):
        """
        Handles creation of the submerchant.

        :param dict submerchant_info: The information to be used in
        submerchant creation.
        :param str user_id: The user's UUID.
        :param bool skip_commit: Handles skipping commit if desired.
        :rtype: dict
        :return: The submerchant's info.
        """
        self._assert_no_duplicate_submerchant(user_id)
        merchant_dao = MerchantDAO()

        account_id = self._make_account_id()
        master_account_id = merchant_dao.get_master_merchant().account_id
        submerchant_info['master_merchant_account_id'] = master_account_id
        submerchant_info['id'] = self._make_account_id()
        register_as_business = submerchant_info['register_as_business']

        result = BraintreeSubmerchant().create_submerchant(submerchant_info)

        if not result.is_success:
            logging.info(
                'Failed to create submerchant under master merchant {0} '
                '-- {1} error: {2}'.format(account_id, submerchant_info,
                                           result))
            raise FacadeException(
                'Failed to create submerchant. {0}'.format(result))

        merchant_dao.create_submerchant(submerchant_info,
                                        register_as_business,
                                        user_id,
                                        skip_commit=skip_commit)

        return submerchant_info
    def create_new_subscription_with_customer(
            self, user_id, nonce, first_name, last_name,
            *, skip_commit=True, plan_id='Basic0x01'):
        """
        Handles creating a new customer with a new subscription.

        :param str user_id: The user to create the customer and subscription
        for.
        :param str nonce: A nonce identifying a card -- created by BT
        hosted fields on the FE.
        :param str first_name: The user's first name.
        :param str last_name: The user's last name.
        :param bool skip_commit: Should we skip committing? Facades on facades
        :param str plan_id: The plan ID. Don't touch!
        :rtype: SubscriptionTable
        :return: The newly created subscription.
        """
        found_customer = self._customer_exists(user_id)
        if found_customer:
            return self.create_new_subscription(
                user_id,
                skip_commit=skip_commit,
                plan_id=plan_id,
            )

        try:
            # type: CustomerTable
            new_customer = self.customer_facade.create_customer(
                nonce,
                first_name,
                last_name,
                user_id,
                skip_commit=skip_commit
            )

            sub_id = uuid.uuid4()

            new_subscription = self.subscription_integration.start_subscription(
                sub_id,
                new_customer.credit_card_token,
                plan_id,
            )

            self.subscription_dao.create_subscription(
                sub_id,
                user_id,
                skip_commit=skip_commit,
            )

            db.session.commit()

            return new_subscription
        except Exception as e:
            logging.error(
                'Failed to create new customer for user {0} with '
                'exception {1}'.format(
                    user_id,
                    e,
                )
            )
            db.session.rollback()
            raise FacadeException(
                'Failed to start subscription.'
            )
Esempio n. 7
0
    def issue_new_payment(self, event, nonce, address):
        """
        Issues a new payment w/in Braintree.

        :param EventTable event: The event that must be paid for.
        :param str nonce: The nonce which signifies which payment method
        is to be used.
        :param AddressTable address: The address information to be used
        whenever issuing a payment.
        :rtype: PaymentTable
        :return: The newly created payment.
        """
        try:
            submerchant = MerchantDAO().get_submerchant_by_id(
                event.scheduled_user_id)
        except DAOException as e:
            logging.error('Invalid event ({0}) issued, no submerchant '
                          '({1}). Exception of: {2}.'.format(
                              event.public_id,
                              event.scheduled_user_id,
                              e,
                          ))
            raise DAOException(e)

        if submerchant is None:
            logging.error(
                'Failed to retrieve submerchant by public ID {0} for a new '
                'event.'.format(event.scheduled_user_id))
            raise FacadeException('Invalid requested user. Contact support.')

        try:
            # TODO(ian): This can be refactored to use
            # EventDAO().get_event_by_id and retrieve all the info in 1 query.
            new_transaction = BraintreeTransactions().create_transaction(
                submerchant,
                event.calculate_total_price(
                    event.duration,
                    UserDAO().get(event.scheduled_user_id),
                ),
                nonce,
                UserDAO().get(event.scheduling_user_id),
                address,
            )

            if isinstance(new_transaction, ErrorResult):
                logging.error('Received error result {0} when creating new '
                              'transaction for event {1}'.format(
                                  new_transaction, event))
                raise FacadeException('Failed to complete transaction.')

            return BraintreePaymentsDAO().insert_new_transaction(
                submerchant,
                event.total_price,
                event.calculate_service_fee(submerchant),
                event,
                skip_commit=True,
            )
        except Exception as e:
            db.session.rollback()
            logging.error(
                'Exception encountered while creating and inserting '
                'transaction: {0}.'.format(e), )
            raise FacadeException(e)