示例#1
0
    def post():
        """Create a new draft statement."""
        try:

            # Quick check: must provide an account ID.
            account_id = get_account_id(request)
            if account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Disable schema validation: draft may be partial/incomplele.
            # valid_format, errors = schema_utils.validate(request_json, 'draft', 'ppr')
            # if not valid_format:
            #   return validation_error_response(errors, VAL_ERROR)

            # Save new draft statement: BusinessException raised if failure.
            draft = Draft.create_from_json(request_json, account_id)
            draft.save()

            return draft.json, HTTPStatus.CREATED

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#2
0
    def get(registration_num):
        """Get a financing statement by registration number."""
        try:
            if registration_num is None:
                return path_param_error_response('registration number')

            # Quick check: must be staff or provide an account ID.
            account_id = get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            # Try to fetch financing statement by registration number
            # Not found or non-staff historical throws a business exception.
            statement = FinancingStatement.find_by_registration_number(registration_num,
                                                                       is_staff(jwt))
            return statement.json, HTTPStatus.OK

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:   # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#3
0
    def post():
        """Create a new financing statement."""
        try:

            # Quick check: must be staff or provide an account ID.
            account_id = get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Validate request data against the schema.
            valid_format, errors = schema_utils.validate(request_json, 'financingStatement', 'ppr')
            if not valid_format:
                return validation_error_response(errors, VAL_ERROR)

            # TODO: charge a fee.

            # Try to save the financing statement: failure throws a business exception.
            statement = FinancingStatement.create_from_json(request_json, account_id)
            statement.save()

            return statement.json, HTTPStatus.CREATED

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:   # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#4
0
    def get(code):
        """Get a preset registering or secured party by client code."""
        try:
            if code is None:
                return resource_utils.path_param_error_response('code')

            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            # Try to fetch client party by code
            current_app.logger.debug(
                f'Getting party code for account {account_id} with code = {code}.'
            )
            party = ClientCode.find_by_code(code)
            if not party:
                return resource_utils.not_found_error_response('party', code)

            return party, HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#5
0
    def put(document_id):
        """Update a draft statement by document ID with data in the request body."""
        try:
            if document_id is None:
                return path_param_error_response('document ID')

            # Quick check: must provide an account ID.
            account_id = get_account_id(request)
            if account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Disable schema validation: draft may be partial/incomplele.
            # valid_format, errors = schema_utils.validate(request_json, 'draft', 'ppr')
            # if not valid_format:
            #   return validation_error_response(errors, VAL_ERROR)

            # Save draft statement update: BusinessException raised if failure.
            draft = Draft.update(request_json, document_id)
            draft.save()

            return draft.json, HTTPStatus.OK

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#6
0
    def get(name_or_code):
        """Get a list of client parties (registering or secured parties) associated with a head office code or name."""
        try:
            if name_or_code is None:
                return resource_utils.path_param_error_response('nameOrCode')
            fuzzy_param = request.args.get(FUZZY_NAME_SEARCH_PARAM)

            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            # Try to fetch client parties: no results is an empty list.
            current_app.logger.debug(
                f'Getting {account_id} head office party codes searching on {name_or_code}.'
            )
            parties = ClientCode.find_by_head_office(name_or_code, fuzzy_param)
            # if not parties:
            #    return resource_utils.not_found_error_response('party', code)
            return jsonify(parties), HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#7
0
    def post(registration_num):
        """Renew a financing statement by registration number."""
        try:
            if registration_num is None:
                return path_param_error_response('registration number')

            # Quick check: must be staff or provide an account ID.
            account_id = get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Validate request data against the schema.
            valid_format, errors = schema_utils.validate(request_json, 'renewalStatement', 'ppr')
            if not valid_format:
                return validation_error_response(errors, VAL_ERROR_RENEWAL)

            # payload base registration number must match path registration number
            if registration_num != request_json['baseRegistrationNumber']:
                return path_data_mismatch_error_response(registration_num,
                                                         'base registration number',
                                                         request_json['baseRegistrationNumber'])

            # Fetch base registration information: business exception thrown if not
            # found or historical.
            statement = FinancingStatement.find_by_registration_number(registration_num, False)

            # Verify base debtor (bypassed for staff)
            if not statement.validate_base_debtor(request_json['baseDebtor'], is_staff(jwt)):
                return base_debtor_invalid_response()

            # TODO: charge a fee.

            # Try to save the renewal statement: failure throws a business exception.
            statement = Registration.create_from_json(request_json,
                                                      model_utils.REG_CLASS_RENEWAL,
                                                      statement,
                                                      registration_num,
                                                      account_id)
            statement.save()

            return statement.json, HTTPStatus.OK

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:   # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#8
0
    def patch():
        """Update user profile UI settings for the user represented by the request JWT."""
        try:
            # Quick check: always require an account ID.
            account_id = resource_utils.get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            current_app.logger.debug(
                f'Updating user profile for {account_id} with values: {request_json}'
            )
            # Validate against the schema.
            if not bypass_validation(request_json):
                valid_format, errors = schema_utils.validate(
                    request_json, 'userProfile', 'common')
                if not valid_format:
                    return resource_utils.validation_error_response(
                        errors, VAL_ERROR)

            token = g.jwt_oidc_token_info
            current_app.logger.debug(
                f'Updating user profile for {account_id} with token: {token}')

            # Try to fetch existing user from JWT.
            user = User.find_by_jwt_token(token)
            if not user:
                # If user does not exist, create user and user profile with the default settings.
                current_app.logger.error(
                    f'Update user profile no user found for {account_id} request token.'
                )
                return resource_utils.not_found_error_response(
                    'user profile', account_id)

            user_profile = user.user_profile
            user_profile.update_profile(request_json)
            return user_profile.json, HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            current_app.logger.error(
                f'Get user profile {account_id} failed: ' +
                repr(default_exception))
            return resource_utils.default_exception_response(default_exception)
示例#9
0
    def post(search_id):
        """Execute a search detail request using selection choices in the request body."""
        try:
            if search_id is None:
                return resource_utils.path_param_error_response('search ID')

            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Validate schema.
            valid_format, errors = schema_utils.validate(
                request_json, 'searchSummary', 'ppr')
            if not valid_format:
                return resource_utils.validation_error_response(
                    errors, VAL_ERROR)

            # Perform any extra data validation such as start and end dates here
            search_detail = SearchResult.validate_search_select(
                request_json, search_id)

            # Save the search query selection and details that match the selection.
            search_detail.update_selection(request_json)
            if not search_detail.search_response:
                return resource_utils.unprocessable_error_response(
                    'search result details')

            response_data = search_detail.json
            if resource_utils.is_pdf(request):
                token = g.jwt_oidc_token_info
                # Return report if request header Accept MIME type is application/pdf.
                return get_pdf(response_data, account_id,
                               ReportTypes.SEARCH_DETAIL_REPORT.value,
                               token['name'])

            return jsonify(response_data), HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#10
0
    def get():
        """Get a list of client parties associated with an account-BCOL number pair."""
        try:
            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            # Try to fetch client parties: no results is an empty list.
            current_app.logger.debug(f'Getting {account_id}  party codes.')
            parties = ClientCode.find_by_account_id(account_id, True)
            return jsonify(parties), HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#11
0
    def get():
        """Get existing user profile UI settings for the user represented by the request JWT."""
        try:
            # Quick check: always require an account ID.
            account_id = resource_utils.get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            token = g.jwt_oidc_token_info
            current_app.logger.debug(
                f'Getting user profile for account {account_id} with token: {token}'
            )

            # Try to fetch existing user from JWT.
            user = User.find_by_jwt_token(token, account_id)
            current_app.logger.debug(
                f'User profile query completed for account {account_id}.')
            if not user:
                # If user does not exist, create user and user profile with the default settings.
                current_app.logger.debug(
                    f'No user found for {account_id} request token: creating records.'
                )
                user = User.create_from_jwt_token(token, account_id)
                user.user_profile = UserProfile.create_from_json(None, user.id)
                user.user_profile.save()

            return user.user_profile.json, HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            current_app.logger.error(
                f'Get user profile {account_id} failed: ' +
                repr(default_exception))
            return resource_utils.default_exception_response(default_exception)
示例#12
0
    def get():
        """Get the list of draft statements belonging to the header account ID."""
        try:

            # Quick check: must provide an account ID.
            account_id = get_account_id(request)
            if account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            # Try to fetch draft list for account ID
            draft_list = Draft.find_all_by_account_id(account_id)

            return jsonify(draft_list), HTTPStatus.OK

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#13
0
    def get():
        """Get account search history."""
        try:
            # Quick check: must have an account ID.
            account_id = resource_utils.get_account_id(request)
            if account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            # Try to fetch search history by account id.
            # No results throws a not found business exception.
            current_app.logger.info(
                f'Fetching search history for {account_id}.')
            history = SearchRequest.find_all_by_account_id(account_id)
            return jsonify(history), HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#14
0
    def put(search_id):
        """Execute a search selection update request replacing the current value with the request body contents."""
        try:
            if search_id is None:
                return resource_utils.path_param_error_response('search ID')

            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Validate schema.
            valid_format, errors = schema_utils.validate(
                request_json, 'searchSummary', 'ppr')
            if not valid_format:
                return resource_utils.validation_error_response(
                    errors, VAL_ERROR)

            search_request = SearchRequest.find_by_id(search_id)
            if not search_request:
                return resource_utils.not_found_error_response(
                    'searchId', search_id)

            # Save the updated search selection.
            search_request.update_search_selection(request_json)
            return jsonify(
                search_request.updated_selection), HTTPStatus.ACCEPTED

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#15
0
    def get(document_id):
        """Get a draft statement by document ID."""
        try:
            if document_id is None:
                return path_param_error_response('document ID')

            # Quick check: must be staff or provide an account ID.
            account_id = get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            # Try to fetch draft statement by document ID
            draft = Draft.find_by_document_number(document_id, False)

            return draft.json, HTTPStatus.OK

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#16
0
    def delete(document_id):
        """Delete a draft statement by document ID."""
        try:
            if document_id is None:
                return path_param_error_response('document ID')

            # Quick check: must be staff or provide an account ID.
            account_id = get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return unauthorized_error_response(account_id)

            # Try to fetch draft statement by document ID
            Draft.delete(document_id)

            return '', HTTPStatus.NO_CONTENT

        except BusinessException as exception:
            return business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return default_exception_response(default_exception)
示例#17
0
    def get(search_id):
        """Get search detail information for a previous search."""
        try:
            if search_id is None:
                return resource_utils.path_param_error_response('search ID')

            # Quick check: must have an account ID.
            account_id = resource_utils.get_account_id(request)
            if account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            # Try to fetch search detail by search id.
            current_app.logger.info(f'Fetching search detail for {search_id}.')
            search_detail = SearchResult.find_by_search_id(search_id, True)
            if not search_detail:
                return resource_utils.not_found_error_response(
                    'searchId', search_id)

            response_data = search_detail.json
            if resource_utils.is_pdf(request):
                token = g.jwt_oidc_token_info
                # Return report if request header Accept MIME type is application/pdf.
                return get_pdf(response_data, account_id,
                               ReportTypes.SEARCH_DETAIL_REPORT.value,
                               token['name'])

            return jsonify(response_data), HTTPStatus.OK

        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#18
0
    def post():  # pylint: disable=too-many-branches
        """Execute a new search request using criteria in the request body."""
        try:
            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if not account_id:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Validate request against the schema.
            valid_format, errors = schema_utils.validate(
                request_json, 'searchQuery', 'ppr')
            if not valid_format:
                return resource_utils.validation_error_response(
                    errors, VAL_ERROR)
            # Perform any extra data validation such as start and end dates here
            SearchRequest.validate_query(request_json)
            # Staff has special payment rules and setup.
            if is_staff_account(account_id) or is_bcol_help(account_id):
                return staff_search(request, request_json, account_id)

            query = SearchRequest.create_from_json(
                request_json, account_id,
                g.jwt_oidc_token_info.get('username', None))

            # Charge a search fee.
            invoice_id = None
            payment = Payment(jwt=jwt.get_token_auth_header(),
                              account_id=account_id,
                              details=get_payment_details(
                                  query, request_json['type']))
            pay_ref = payment.create_payment(TransactionTypes.SEARCH.value, 1,
                                             None, query.client_reference_id)
            invoice_id = pay_ref['invoiceId']
            query.pay_invoice_id = int(invoice_id)
            query.pay_path = pay_ref['receipt']

            # Execute the search query: treat no results as a success.
            try:
                query.search()

                # Now save the initial detail results in the search_result table with no
                # search selection criteria (the absence indicates an incomplete search).
                search_result = SearchResult.create_from_search_query(query)
                search_result.save()

            except Exception as db_exception:  # noqa: B902; handle all db related errors.
                current_app.logger.error(
                    SAVE_ERROR_MESSAGE.format(account_id, repr(db_exception)))
                if invoice_id is not None:
                    current_app.logger.info(
                        PAY_REFUND_MESSAGE.format(account_id, invoice_id))
                    try:
                        payment.cancel_payment(invoice_id)
                    except Exception as cancel_exception:  # noqa: B902; log exception
                        current_app.logger.error(
                            PAY_REFUND_ERROR.format(account_id, invoice_id,
                                                    repr(cancel_exception)))

                raise db_exception

            return query.json, HTTPStatus.CREATED

        except SBCPaymentException as pay_exception:
            return resource_utils.pay_exception_response(pay_exception)
        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)
示例#19
0
    def post():
        """Execute a new search request using criteria in the request body."""
        try:

            # Quick check: must be staff or provide an account ID.
            account_id = resource_utils.get_account_id(request)
            if not is_staff(jwt) and account_id is None:
                return resource_utils.account_required_response()

            # Verify request JWT and account ID
            if not authorized(account_id, jwt):
                return resource_utils.unauthorized_error_response(account_id)

            request_json = request.get_json(silent=True)
            # Validate request against the schema.
            valid_format, errors = schema_utils.validate(
                request_json, 'searchQuery', 'ppr')
            if not valid_format:
                return resource_utils.validation_error_response(
                    errors, VAL_ERROR)
            # Perform any extra data validation such as start and end dates here
            SearchClient.validate_query(request_json)
            query = SearchClient.create_from_json(request_json, account_id)

            # Charge a search fee.
            if account_id:
                payment = Payment(jwt=jwt.get_token_auth_header(),
                                  account_id=account_id)
                pay_ref = payment.create_payment(TransactionTypes.SEARCH.value,
                                                 1, None,
                                                 query.client_reference_id)
                invoice_id = pay_ref['invoiceId']
                query.pay_invoice_id = int(invoice_id)
                query.pay_path = pay_ref['receipt']

            # Execute the search query: treat no results as a success.
            try:
                query.search()
                # if not query.search_response or query.returned_results_size == 0:
                #   return resource_utils.unprocessable_error_response('search query')

                # Now save the initial detail results in the search_result table with no
                # search selection criteria (the absence indicates an incomplete search).
                search_result = SearchResult.create_from_search_query(query)
                search_result.save()

            except Exception as db_exception:  # noqa: B902; handle all db related errors.
                current_app.logger.error(
                    f'Search {account_id} db save failed: ' +
                    repr(db_exception))
                current_app.logger.error(
                    f'Search {account_id} rolling back payment for invoice {invoice_id}.'
                )
                try:
                    payment.cancel_payment(invoice_id)
                except Exception as cancel_exception:  # noqa: B902; log exception
                    current_app.logger.error(
                        f'Search {account_id} payment refund failed for invoice {invoice_id}: '
                        + repr(cancel_exception))

                raise db_exception

            return query.json, HTTPStatus.CREATED

        except SBCPaymentException as pay_exception:
            return resource_utils.pay_exception_response(pay_exception)
        except BusinessException as exception:
            return resource_utils.business_exception_response(exception)
        except Exception as default_exception:  # noqa: B902; return nicer default error
            return resource_utils.default_exception_response(default_exception)