def get(self, kyc_application_id):

        user_id = request.args.get('user_id')

        trulioo_countries = request.args.get('trulioo_countries', None)
        trulioo_documents = request.args.get('trulioo_documents', None)
        country = request.args.get('country', None)

        if trulioo_countries:
            trulioo_countries = supported_countries
            return make_response(jsonify({'message': 'Trulioo Countries', 'data': {'kyc_application': {'trulioo_countries': trulioo_countries}}})), 200

        if trulioo_documents:
            trulioo_documents = {country: supported_documents[country]}
            return make_response(jsonify({'message': 'Trulioo Countries', 'data': {'kyc_application': {'trulioo_documents': trulioo_documents}}})), 200

        if AccessControl.has_suffient_role(g.user.roles, {'ADMIN': 'subadmin'}):
            if user_id:
                # user account KYC
                kyc_details = KycApplication.query.filter_by(user_id=user_id).first()
            else:
                # main organisation KYC
                kyc_details = KycApplication.query.filter_by(organisation_id=g.active_organisation.id).first()

            if kyc_details is None:
                response_object = {
                    'message': 'No business verification details found'
                }

                return make_response(jsonify(response_object)), 404

            if user_id and AccessControl.has_suffient_role(g.user.roles, {'ADMIN': 'admin'}):
                response_object = {
                    'message': 'Successfully loaded business verification details',
                    'data': {'kyc_application': kyc_application_schema.dump(kyc_details).data}
                }

                return make_response(jsonify(response_object)), 200

        else:
            # must be an individual (mobile) user account
            kyc_details = KycApplication.query.filter_by(user_id=g.user.id).first()
            if kyc_details is None:
                return make_response(jsonify({'message': 'No KYC object found for user.', 'data': {'kyc_application': {}}}))

        # displays kyc_status and kyc_actions state only.
        response_object = {
            'message': 'Loaded KYC details',
            'data': {'kyc_application': kyc_application_state_schema.dump(kyc_details).data}
        }

        return make_response(jsonify(response_object)), 200
    def get(self):

        user = g.user

        if AccessControl.has_suffient_role(user.roles, {'ADMIN': 'subadmin', 'VENDOR': 'supervendor'}):
            # admins and supervendors see all transfers for that transfer account
            transfer_account = user.transfer_account

            transfers_query = CreditTransfer.query.filter(
                or_(CreditTransfer.recipient_transfer_account_id == transfer_account.id,
                    CreditTransfer.sender_transfer_account_id == transfer_account.id))

        else:
            # other users only see transfers involving themselves
            transfers_query = CreditTransfer.query.filter(
                or_(CreditTransfer.recipient_user_id == user.id,
                    CreditTransfer.sender_user_id == user.id))

        transfers, total_items, total_pages = paginate_query(transfers_query, CreditTransfer)

        transfer_list = me_credit_transfers_schema.dump(transfers).data

        response_object = {
            'message': 'Successfully Loaded.',
            'items': total_items,
            'pages': total_pages,
            'data': {
                'credit_transfers': transfer_list,
            }
        }

        return make_response(jsonify(response_object)), 201
    def resolve_as_complete(self, batch_uuid=None):
        if self.transfer_status not in [None, TransferStatusEnum.PENDING]:
            raise Exception(f'Resolve called multiple times for transfer {self.id}')
        try:
            self.check_sender_transfer_limits()
        except TransferLimitError as e:
            # Sempo admins can always bypass limits, allowing for things like emergency moving of funds etc
            if hasattr(g, 'user') and AccessControl.has_suffient_role(g.user.roles, {'ADMIN': 'sempoadmin'}):
                self.add_message(f'Warning: {e}')
            else:
                raise e

        self.resolved_date = datetime.datetime.utcnow()
        self.transfer_status = TransferStatusEnum.COMPLETE
        self.update_balances()

        if self.transfer_type == TransferTypeEnum.PAYMENT and self.transfer_subtype == TransferSubTypeEnum.DISBURSEMENT:
            if self.recipient_user and self.recipient_user.transfer_card:
                self.recipient_user.transfer_card.update_transfer_card()

        if batch_uuid:
            self.batch_uuid = batch_uuid

        if self.fiat_ramp and self.transfer_type in [TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL]:
            self.fiat_ramp.resolve_as_complete()
    def post(self):
        reference = None
        kyc_application_id = None

        if 'kyc_application_id' in request.form:
            kyc_application_id = request.form['kyc_application_id']

        if 'document' not in request.files:
            return make_response(jsonify({'message': 'No File'})), 400

        document = request.files['document']
        filename = document.filename

        if kyc_application_id is None:
            return make_response(jsonify({'message': 'You must append documents to a business profile'})), 400

        business_details = KycApplication.query.filter_by(id=kyc_application_id).first()

        if not business_details:
            return make_response(jsonify({'message': 'Cannot find kyc for id {}'.format(kyc_application_id)})), 404

        if business_details.organisation_id and AccessControl.has_suffient_role(g.user.roles, {'ADMIN': 'superadmin'}) is not True:
            return make_response(jsonify({'message': 'Must be a superadmin to edit admin org KYC object'})), 401

        if filename == '':
            return make_response(jsonify({'message': 'No File'})), 400

        if not allowed_file(filename):
            return make_response(jsonify({'message': 'Must be JPG, JPEG, PNG or PDF'})), 400

        file_type = filename.rsplit('.', 1)[1].lower()
        new_filename = generate_new_filename(filename, file_type)

        saved_document = UploadedResource.query.filter_by(filename=new_filename).first()

        if saved_document:
            return make_response(jsonify({'message': 'Document already exists'})), 400

        save_to_s3_from_document(document=document, new_filename=new_filename)

        if 'reference' in request.form:
            reference = request.form['reference']

        uploaded_document = UploadedResource(filename=new_filename, file_type=file_type,
                                             reference=reference, user_filename=filename)
        db.session.add(uploaded_document)

        # tie document to kyc application
        uploaded_document.kyc_application_id = business_details.id

        response_object = {
            'message': 'Document uploaded',
            'data': {'kyc_application': kyc_application_schema.dump(business_details).data}
        }

        return make_response(jsonify(response_object)), 201
    def put(self, bank_account_id):

        put_data = request.get_json()

        kyc_application_id = put_data.get('kyc_application_id')

        bank_country = put_data.get('bank_country')
        routing_number = put_data.get('routing_number')
        account_number = put_data.get('account_number')
        currency = put_data.get('currency')

        if bank_account_id is None:
            return make_response(
                jsonify({'message':
                         'You need to provide a bank account ID'})), 400

        bank_account = BankAccount.query.filter_by(id=bank_account_id).first()

        if kyc_application_id is None:
            kyc_application_id = bank_account.kyc_application_id

        business_details = KycApplication.query.filter_by(
            id=kyc_application_id).first()

        if not business_details:
            return make_response(
                jsonify({
                    'message':
                    'Cannot find kyc for id {}'.format(kyc_application_id)
                })), 404

        if business_details.organisation_id and AccessControl.has_suffient_role(
                g.user.roles, {'ADMIN': 'superadmin'}) is not True:
            return make_response(
                jsonify({
                    'message':
                    'Must be a superadmin to edit admin org KYC object'
                })), 401

        if bank_account:
            bank_account.kyc_application_id = kyc_application_id
            bank_account.bank_country = bank_country
            bank_account.routing_number = routing_number
            bank_account.account_number = account_number
            bank_account.currency = currency

        response_object = {
            'message': 'Bank account edited',
            'data': {
                'kyc_application':
                kyc_application_schema.dump(business_details).data
            }
        }

        return make_response(jsonify(response_object)), 200
    def post(self, bank_account_id):
        post_data = request.get_json()

        kyc_application_id = post_data.get('kyc_application_id')

        bank_country = post_data.get('bank_country')
        routing_number = post_data.get('routing_number')
        account_number = post_data.get('account_number')
        currency = post_data.get('currency')

        business_details = KycApplication.query.filter_by(id=kyc_application_id).first()

        if not business_details:
            return make_response(jsonify({'message': 'Cannot find kyc for id {}'.format(kyc_application_id)})), 404

        if business_details.organisation_id and AccessControl.has_suffient_role(g.user.roles,
                                                                                {'ADMIN': 'superadmin'}) is not True:
            return make_response(jsonify({'message': 'Must be a superadmin to edit admin org KYC object'})), 401

        if routing_number is None or account_number is None or bank_country is None or currency is None or kyc_application_id is None:
            response_object = {
                'message': 'Need routing_number, account_number, bank_country, currency and business profile id',
            }

            return make_response(jsonify(response_object)), 400

        # can't create a duplicate bank account at present
        bank_account = BankAccount.query.filter_by(routing_number=routing_number, account_number=account_number).first()

        if bank_account:
            response_object = {
                'message': 'Bank account already exists',
            }

            return make_response(jsonify(response_object)), 400

        # create new bank account
        create_bank_account = BankAccount(
            bank_country=bank_country,
            routing_number=routing_number,
            account_number=account_number,
            currency=currency,
        )

        create_bank_account.kyc_application = business_details

        db.session.add(create_bank_account)

        response_object = {
            'message': 'Bank account added',
            'data': {'kyc_application': kyc_application_schema.dump(business_details).data}
        }

        return make_response(jsonify(response_object)), 201
示例#7
0
    def wrapper(*args, **kwargs):

        # ----- FIRST GET AUTH VALUES -----

        # Query string auth needs to be explicity allowed for an endpoint since it can lead to security vulnerabilities
        # if used incorrectly by the client (for example credentials getting logged by website trackers).
        # We get credentials with it first, meaning any values will be overwritten by a present header auth
        if allow_query_string_auth:
            username = request.args.get('username', None)
            password = request.args.get('password', None)

            auth_token = request.args.get('auth_token', None)
            tfa_token = request.args.get('tfa_token', None)
        else:
            username = None
            password = None
            auth_token = None
            tfa_token = None

        # Next get basic auth, which we parse using flask's built-in process, if present overwriting query string values
        auth = request.authorization
        if auth and auth.type == 'basic':
            username = auth.username or username
            password = auth.password or password

        # Lastly, get any custom set Sempo auth headers, if present overwriting query string values
        auth_header = request.headers.get('Authorization')
        if auth_header:
            split_header = auth_header.split("|")
            auth_token = split_header[0]
            try:
                tfa_token = split_header[1]
            except IndexError:
                # Auth header does not contain a TFA token, try getting it from explicit header instead
                # (dev convenience)
                tfa_token = request.headers.get(
                    'TFA_Authorization') or tfa_token

        # ----- THEN ATTEMPT AUTHORIZATION -----

        # If username as password attempt basic auth
        if username and password:

            # Make sure basic auth is allowed
            if len(allowed_basic_auth_types) == 0:
                response_object = {'message': 'basic auth not allowed'}
                return make_response(jsonify(response_object)), 401

            # Try to find a matching password and auth type for the username, checking orgs first and then config
            # Check if username belongs to an org
            org = Organisation.query.filter_by(
                external_auth_username=username).first()
            if org:
                auth_type = 'external'
                required_password = org.external_auth_password

            # Otherwise, check if it is one of the allowed BASIC_AUTH_CREDENTIALS
            else:
                try:
                    (required_password, auth_type
                     ) = current_app.config['BASIC_AUTH_CREDENTIALS'][username]
                except KeyError:
                    required_password = None
                    auth_type = None

            g.auth_type = auth_type
            if required_password is None or required_password != password:
                response_object = {
                    'message': 'invalid basic auth username or password'
                }
                return make_response(jsonify(response_object)), 401

            if (auth_type
                    not in allowed_basic_auth_types) or (auth_type is None):
                response_object = {
                    'message':
                    'Basic Auth type is {}. Must be: {}'.format(
                        auth_type, allowed_basic_auth_types)
                }
                return make_response(jsonify(response_object)), 401

            g.active_organisation = org

            return f(*args, **kwargs)

        if auth_token:

            resp = User.decode_auth_token(auth_token)

            if not isinstance(resp, str):

                user = User.query.filter_by(id=resp['id']).execution_options(
                    show_all=True).first()

                if not user:
                    response_object = {
                        'status': 'fail',
                        'message': 'user not found'
                    }
                    return make_response(jsonify(response_object)), 401

                if not user.is_activated:
                    response_object = {
                        'status': 'fail',
                        'message': 'user not activated'
                    }
                    return make_response(jsonify(response_object)), 401

                if user.is_disabled:
                    response_object = {
                        'status': 'fail',
                        'message': 'user has been disabled'
                    }
                    return make_response(jsonify(response_object)), 401

                tfa_response_object = tfa_logic(user, tfa_token,
                                                ignore_tfa_requirement)
                if tfa_response_object:
                    return make_response(jsonify(tfa_response_object)), 401

                if len(allowed_roles) > 0:
                    held_roles = resp.get('roles', {})

                    if not AccessControl.has_suffient_role(
                            held_roles, allowed_roles):
                        response_object = {
                            'message':
                            'user does not have any of the allowed roles: ' +
                            str(allowed_roles),
                        }
                        return make_response(jsonify(response_object)), 403

                # ----- AUTH PASSED, DO FINAL SETUP -----

                g.user = user
                g.member_organisations = [org.id for org in user.organisations]
                try:
                    g.active_organisation = None

                    # First try to set the active org from the query
                    query_org = request.args.get('org', None)
                    if query_org is not None:
                        try:
                            query_org = int(query_org)
                            if query_org in g.member_organisations:
                                g.active_organisation = Organisation.query.get(
                                    query_org)
                        except ValueError:
                            pass

                    # Then get the fallback organisation
                    if g.active_organisation is None:
                        g.active_organisation = user.fallback_active_organisation(
                        )

                    # Check for query_organisations as well. These are stored in g and used for operations which
                    # are allowed to be run against multiple orgs. Submitted as a CSV
                    # E.g. GET metrics, user list, transfer list should be gettable with ?query_organisations=1,2,3
                    query_organisations = request.args.get(
                        'query_organisations', None)
                    if query_organisations:
                        g.query_organisations = []
                        try:
                            query_organisations = [
                                int(q) for q in query_organisations.split(',')
                            ]
                            if set(query_organisations).issubset(
                                    set(g.member_organisations)):
                                g.query_organisations = query_organisations
                        except ValueError:
                            pass

                except NotImplementedError:
                    g.active_organisation = None

                proxies = request.headers.getlist("X-Forwarded-For")
                check_ip(proxies, user, num_proxy=1)

                # updates the validated user last seen timestamp
                user.update_last_seen_ts()

                #This is the point where you've made it through ok and you can return the top method
                return f(*args, **kwargs)

            response_object = {'status': 'fail', 'message': resp}
            return make_response(jsonify(response_object)), 401

        response_object = {
            'status': 'fail',
            'message': 'Provide a valid auth token.'
        }
        return make_response(jsonify(response_object)), 401
示例#8
0
    def get(self, user_id):

        can_see_full_details = AccessControl.has_suffient_role(
            g.user.roles, {'ADMIN': 'admin'})

        if not can_see_full_details:
            public_serial_number = request.args.get('public_serial_number')

            if public_serial_number:
                user = User.query.filter_by(
                    public_serial_number=public_serial_number.strip()).first()

                if user:

                    if user.default_transfer_account:
                        response_object = {
                            'message': 'Successfully found transfer account!',
                            'data': {
                                'balance':
                                user.default_transfer_account.balance
                            }
                        }

                        return make_response(jsonify(response_object)), 201

                    response_object = {
                        'message':
                        'No transfer_account for user: {}'.format(user),
                    }

                    return make_response(jsonify(response_object)), 400

                response_object = {
                    'message':
                    'No user for public serial number: {}'.format(
                        public_serial_number),
                }

                return make_response(jsonify(response_object)), 400

            response_object = {
                'message': 'No public_serial_number provided',
            }

            return make_response(jsonify(response_object)), 400

        account_type_filter = request.args.get('account_type')
        if account_type_filter:
            account_type_filter = account_type_filter.lower()

        if user_id:
            user = User.query.get(user_id)
            #
            # user.cashout_authorised()

            if user is None:
                response_object = {
                    'message': 'No such user: {}'.format(user_id),
                }

                return make_response(jsonify(response_object)), 400

            response_object = {
                'status': 'success',
                'message': 'Successfully Loaded.',
                'data': {
                    'user': user_schema.dump(user).data
                }
            }

            return make_response(jsonify(response_object)), 200

        else:
            if account_type_filter == 'beneficiary':
                user_query = User.query.filter(User.has_beneficiary_role)

            elif account_type_filter == 'vendor':
                user_query = User.query.filter(User.has_vendor_role)

            elif account_type_filter == 'admin':
                user_query = User.query.filter(User.has_admin_role).order_by(
                    User.created.desc())

            else:
                user_query = User.query

            users, total_items, total_pages = paginate_query(user_query, User)

            if users is None:
                response_object = {
                    'message': 'No users',
                }

                return make_response(jsonify(response_object)), 400

            user_list = users_schema.dump(users).data

            response_object = {
                'message': 'Successfully Loaded.',
                'pages': total_pages,
                'items': total_items,
                'data': {
                    'users': user_list,
                }
            }
            return make_response(jsonify(response_object)), 200
    def post(self, kyc_application_id):
        post_data = request.get_json()

        is_mobile = post_data.get('is_mobile')
        user_id = post_data.get(
            'user_id'
        )  # should only be defined when an admin is adding user KYC data (not their own)

        type = post_data.get('account_type', 'BUSINESS').upper()
        first_name = post_data.get('first_name')
        last_name = post_data.get('last_name')
        phone = post_data.get('phone')
        business_legal_name = post_data.get('business_legal_name')
        business_type = post_data.get('business_type')
        tax_id = post_data.get('tax_id')
        website = post_data.get('website')
        date_established = post_data.get('date_established')
        country = post_data.get('country')
        street_address = post_data.get('street_address')
        street_address_2 = post_data.get('street_address_2')
        city = post_data.get('city')
        region = post_data.get('region')
        postal_code = post_data.get('postal_code')
        beneficial_owners = post_data.get('beneficial_owners')

        document_type = post_data.get('document_type')
        document_country = post_data.get('document_country')
        document_front_base64 = post_data.get('document_front_base64')  # image
        document_back_base64 = post_data.get('document_back_base64')  # image
        selfie_base64 = post_data.get('selfie_base64')  # image

        if is_mobile or user_id:

            # creation logic is handled after kyc object creation.
            kyc_details = KycApplication.query.filter_by(
                user_id=user_id or g.user.id).first()
            if kyc_details is not None:
                return make_response(
                    jsonify({'message': 'KYC details already exist'})), 400

            if not user_id and (document_type is None
                                or document_country is None
                                or document_front_base64 is None
                                or selfie_base64 is None):
                return make_response(
                    jsonify({'message':
                             'Must provide correct parameters'})), 400

        if not is_mobile and type == 'BUSINESS':

            if user_id and AccessControl.has_suffient_role(
                    g.user.roles, {'ADMIN': 'subadmin'}) is not True:
                return make_response(
                    jsonify({
                        'message':
                        'Must be superadmin to create any KYC profile'
                    })), 401

            elif AccessControl.has_suffient_role(
                    g.user.roles, {'ADMIN': 'superadmin'}) is not True:
                return make_response(
                    jsonify({
                        'message':
                        'Must be superadmin to create org business KYC profile'
                    })), 401

            # check for existing business based on Legal Name and Tax ID.
            business_details = KycApplication.query.filter_by(
                business_legal_name=business_legal_name,
                tax_id=tax_id).first()

            if business_details is not None:
                response_object = {
                    'message':
                    'Business Verification profile already exists for business name: {} and tax ID: {}'
                    .format(business_legal_name, tax_id)
                }

                return make_response(jsonify(response_object)), 400

        if not is_mobile and (business_legal_name is None
                              and tax_id is None) and not user_id:
            # not mobile, not a org profile, thus user_id cannot be None
            return make_response(
                jsonify({
                    'message':
                    'Must provide a user id to create a user KYC profile'
                })), 400

        if beneficial_owners is not None:
            # filter empty beneficial owners
            beneficial_owners = [
                owner for owner in beneficial_owners
                if (owner['full_name'].strip(' ', ) != '')
            ]

        create_kyc_application = KycApplication(
            type=type,
            user=g.user,
            first_name=first_name or g.user.first_name,
            last_name=last_name or g.user.last_name,
            phone=phone or g.user.phone,
            business_legal_name=business_legal_name,
            business_type=business_type,
            tax_id=tax_id,
            website=website,
            date_established=date_established,
            country=country or document_country,
            street_address=street_address,
            street_address_2=street_address_2,
            city=city,
            region=region,
            postal_code=postal_code,
            beneficial_owners=beneficial_owners,
        )

        if user_id:
            user = User.query.get(user_id)
            create_kyc_application.user = user or g.user

        if not is_mobile:
            # not mobile
            if not user_id and type == 'BUSINESS':
                # not a admin applying for another user
                # ngo organisation
                create_kyc_application.organisation = g.active_organisation
            else:
                # admin applying for another user (individual or business)
                create_kyc_application.kyc_status = 'INCOMPLETE'

        db.session.add(create_kyc_application)
        db.session.flush()  # need this to create an ID

        if is_mobile:
            # handle document upload to s3
            handle_kyc_documents(data=post_data,
                                 document_country=document_country,
                                 document_type=document_type,
                                 kyc_details=create_kyc_application)

            # Post verification message to slack
            post_verification_message(user=g.user)

        response_object = {
            'message': 'KYC Application created',
            'data': {
                'kyc_application':
                kyc_application_state_schema.dump(create_kyc_application).data
            }
        }

        return make_response(jsonify(response_object)), 201
    def put(self, kyc_application_id):
        put_data = request.get_json()

        is_mobile = put_data.get('is_mobile')

        document_type = put_data.get('document_type')
        document_country = put_data.get('document_country')
        document_front_base64 = put_data.get('document_front_base64')  # image
        document_back_base64 = put_data.get('document_back_base64')  # image
        selfie_base64 = put_data.get('selfie_base64')  # image

        kyc_status = put_data.get('kyc_status')
        first_name = put_data.get('first_name')
        last_name = put_data.get('last_name')
        phone = put_data.get('phone')
        business_legal_name = put_data.get('business_legal_name')
        business_type = put_data.get('business_type')
        tax_id = put_data.get('tax_id')
        website = put_data.get('website')
        date_established = put_data.get('date_established')
        country = put_data.get('country')
        street_address = put_data.get('street_address')
        street_address_2 = put_data.get('street_address_2')
        city = put_data.get('city')
        region = put_data.get('region')
        postal_code = put_data.get('postal_code')
        beneficial_owners = put_data.get('beneficial_owners')

        kyc_details = None

        if is_mobile:
            if document_type is None or document_country is None or document_front_base64 is None or selfie_base64 is None:
                return make_response(
                    jsonify({'message':
                             'Must provide correct parameters'})), 400

            kyc_details = KycApplication.query.filter_by(
                user_id=g.user.id).first()
            if kyc_details is None:
                return make_response(
                    jsonify({'message': 'No KYC object found'})), 400

            kyc_details.kyc_attempts = kyc_details.kyc_attempts + 1

            if kyc_details.kyc_attempts > 2:
                # only allow two attempts
                kyc_details.kyc_status = 'REJECTED'
                db.session.commit()
                return make_response(
                    jsonify(
                        {'message':
                         'KYC attempts exceeded. Contact Support.'})), 400

            kyc_details.kyc_status = 'PENDING'

            # handle document upload to s3
            handle_kyc_documents(data=put_data,
                                 document_country=document_country,
                                 document_type=document_type,
                                 kyc_details=kyc_details)

            # Post verification message to slack
            post_verification_message(user=g.user)

            response_object = {
                'message': 'Successfully Updated KYC Application.',
                'data': {
                    'kyc_application':
                    kyc_application_schema.dump(kyc_details).data
                }
            }

            return make_response(jsonify(response_object)), 200

        if not is_mobile:
            if kyc_application_id is None:
                response_object = {
                    'message': 'Must provide business profile ID'
                }
                return make_response(jsonify(response_object)), 400

            kyc_details = KycApplication.query.get(kyc_application_id)

            if not kyc_details:
                response_object = {
                    'message': 'Business Verification Profile not found'
                }
                return make_response(jsonify(response_object)), 404

            if kyc_details.organisation_id and AccessControl.has_suffient_role(
                    g.user.roles, {'ADMIN': 'superadmin'}) is not True:
                return make_response(
                    jsonify({
                        'message':
                        'Must be a superadmin to edit admin org KYC object'
                    })), 401

            if AccessControl.has_suffient_role(
                    g.user.roles, {'ADMIN': 'subadmin'}) is not True:
                return make_response(
                    jsonify({
                        'message':
                        'Must be a subadmin to edit any KYC object'
                    })), 401

            # update business profile
            if kyc_status:
                kyc_details.kyc_status = kyc_status
            if first_name:
                kyc_details.first_name = first_name
            if last_name:
                kyc_details.last_name = last_name
            if phone:
                kyc_details.phone = phone
            if business_legal_name:
                kyc_details.business_legal_name = business_legal_name
            if business_type:
                kyc_details.business_type = business_type
            if tax_id:
                kyc_details.tax_id = tax_id
            if website:
                kyc_details.website = website
            if date_established:
                kyc_details.date_established = date_established
            if country:
                kyc_details.country = country
            if street_address:
                kyc_details.street_address = street_address
            if street_address_2:
                kyc_details.street_address_2 = street_address_2
            if city:
                kyc_details.city = city
            if region:
                kyc_details.region = region
            if postal_code:
                kyc_details.postal_code = postal_code

            if beneficial_owners is not None:
                # filter empty beneficial owners
                beneficial_owners = [
                    owner for owner in beneficial_owners
                    if (owner['full_name'].strip(' ', ) != '')
                ]

            if beneficial_owners:
                kyc_details.beneficial_owners = beneficial_owners

            if kyc_status == 'PENDING':
                # Final web submission. Post verification message to slack
                post_verification_message(user=kyc_details.user)

        response_object = {
            'message': 'Successfully Updated KYC Application.',
            'data': {
                'kyc_application':
                kyc_application_schema.dump(kyc_details).data
            }
        }

        return make_response(jsonify(response_object)), 200
示例#11
0
    def post(self, organisation_id):
        post_data = request.get_json()

        organisation_name = post_data.get('organisation_name')
        custom_welcome_message_key = post_data.get(
            'custom_welcome_message_key')
        timezone = post_data.get('timezone')

        country_code = post_data.get('country_code')
        default_disbursement = post_data.get('default_disbursement')
        minimum_vendor_payout_withdrawal = post_data.get(
            'minimum_vendor_payout_withdrawal')
        require_transfer_card = post_data.get('require_transfer_card')
        default_lat = post_data.get('default_lat')
        default_lng = post_data.get('default_lng')
        account_types = post_data.get('account_types', [])

        token_id = post_data.get('token_id')
        deploy_cic = post_data.get('deploy_cic', False)

        for at in account_types:
            if at not in ASSIGNABLE_TIERS.keys():
                raise Exception(f'{at} not an assignable role')

        if organisation_name is None or country_code is None or timezone is None:
            return make_response(
                jsonify({
                    'message':
                    'Must provide organisation_name, country_code and timezone to create organisation.'
                })), 400

        existing_organisation = Organisation.query.filter_by(
            name=organisation_name).execution_options(show_all=True).first()
        if existing_organisation is not None:
            return make_response(
                jsonify({
                    'message':
                    'Must be unique name. Organisation already exists for name: {}'
                    .format(organisation_name),
                    'data': {
                        'organisation':
                        organisation_schema.dump(existing_organisation).data
                    }
                })), 400

        try:
            new_organisation = Organisation(
                name=organisation_name,
                custom_welcome_message_key=custom_welcome_message_key,
                timezone=timezone,
                country_code=country_code,
                default_disbursement=default_disbursement,
                minimum_vendor_payout_withdrawal=
                minimum_vendor_payout_withdrawal,
                require_transfer_card=require_transfer_card,
                default_lat=default_lat,
                default_lng=default_lng,
                valid_roles=account_types)
        except Exception as e:
            response_object = {
                'message': str(e),
            }
            return make_response(jsonify(response_object)), 400

        db.session.add(new_organisation)
        db.session.flush()

        response_object = {
            'message': 'Created Project',
            'data': {
                'organisation': organisation_schema.dump(new_organisation).data
            },
        }

        if token_id:
            token = Token.query.get(token_id)
            if token is None:
                return make_response(jsonify({'message':
                                              'Token not found'})), 404
            new_organisation.bind_token(token)

        elif deploy_cic:

            cic_response_object, cic_response_code = deploy_cic_token(
                post_data, new_organisation)
            if cic_response_code == 201:
                response_object['data']['token_id'] = cic_response_object[
                    'data']['token_id']
            else:
                return make_response(
                    jsonify(cic_response_object)), cic_response_code

        if AccessControl.has_suffient_role(g.user.roles,
                                           {'ADMIN': 'superadmin'}):
            g.user.add_user_to_organisation(new_organisation, is_admin=True)

        return make_response(jsonify(response_object)), 201