Example #1
0
def consume_nr(
        business: Business,
        filing: Filing,
        nr_num_path='/filing/incorporationApplication/nameRequest/nrNumber'):
    """Update the nr to a consumed state."""
    try:
        nr_num = get_str(filing.filing_json, nr_num_path)
        # skip this if none (nrNumber will not be available for numbered company)
        if nr_num:
            bootstrap = RegistrationBootstrap.find_by_identifier(
                filing.temp_reg)
            namex_svc_url = current_app.config.get('NAMEX_API')
            token = AccountService.get_bearer_token()

            # Create an entity record
            data = json.dumps({'consume': {'corpNum': business.identifier}})
            rv = requests.patch(
                url=''.join([namex_svc_url, nr_num]),
                headers={
                    **AccountService.CONTENT_TYPE_JSON, 'Authorization':
                    AccountService.BEARER + token
                },
                data=data,
                timeout=AccountService.timeout)
            if not rv.status_code == HTTPStatus.OK:
                raise QueueException

            # remove the NR from the account
            AccountService.delete_affiliation(bootstrap.account, nr_num)
    except KeyError:
        pass  # return
    except Exception:  # pylint: disable=broad-except; note out any exception, but don't fail the call
        sentry_sdk.capture_message(
            f'Queue Error: Consume NR error for filing:{filing.id}',
            level='error')
Example #2
0
def account(app):
    """Create an account to be used for testing."""
    with app.app_context():
        account_url = current_app.config.get('ACCOUNT_SVC_AFFILIATE_URL')
        account_url = account_url[:account_url.rfind('{') - 1]

        org_data = json.dumps({'name': str(uuid.uuid4())})
        token = AccountService.get_bearer_token()

        # with app.app_context():
        rv = requests.post(
            url=account_url,
            data=org_data,
            headers={
                **AccountService.CONTENT_TYPE_JSON, 'Authorization':
                AccountService.BEARER + token
            },
            timeout=20)

        account_id = rv.json()['id']

        yield account_id

        rv = requests.delete(
            url=f'{account_url}/{account_id}',
            headers={'Authorization': AccountService.BEARER + token},
            timeout=20)
        print(rv)
Example #3
0
async def send_outstanding_bcomps_ar_reminder(app: Flask, qsm: QueueService):  # pylint: disable=redefined-outer-name
    """Find outstanding bcomps to send annual report reminder."""
    try:
        # get token
        token = AccountService.get_bearer_token()
        ar_fee = get_ar_fee(app, Business.LegalTypes.BCOMP.value, token)

        app.logger.debug('Getting outstanding bcomps to send AR reminder')
        where_clause = text(
            'CASE WHEN last_ar_date IS NULL THEN date(founding_date) ELSE date(last_ar_date) END'
            + " <= CURRENT_DATE - interval '1 year'")
        businesses = db.session.query(Business).filter(
            Business.legal_type == Business.LegalTypes.BCOMP.value,
            where_clause).all()
        app.logger.debug('Processing outstanding bcomps to send AR reminder')

        for business in businesses:
            ar_year = (business.last_ar_year if business.last_ar_year else
                       business.founding_date.year) + 1

            await send_email(business.id, ar_fee, str(ar_year), app, qsm)
            app.logger.debug(
                f'Successfully queued ar reminder for business id {business.id} for year {ar_year}.'
            )

    except Exception as err:  # pylint: disable=broad-except, unused-variable # noqa F841;
        app.logger.error(err)
Example #4
0
async def find_and_send_ar_reminder(app: Flask, qsm: QueueService):  # pylint: disable=redefined-outer-name
    """Find business to send annual report reminder."""
    try:
        legal_types = [Business.LegalTypes.BCOMP.value
                       ]  # entity types to send ar reminder
        ar_fees = {}

        # get token
        token = AccountService.get_bearer_token()
        for legal_type in legal_types:
            ar_fees[legal_type] = get_ar_fee(app, legal_type, token)

        app.logger.debug('Getting businesses to send AR reminder today')
        businesses = get_businesses(legal_types)
        app.logger.debug('Processing businesses to send AR reminder')
        for business in businesses:
            ar_year = (business.last_ar_year if business.last_ar_year else
                       business.founding_date.year) + 1

            await send_email(business.id, ar_fees[business.legal_type],
                             str(ar_year), app, qsm)
            app.logger.debug(
                f'Successfully queued ar reminder for business id {business.id}.'
            )

    except Exception as err:  # pylint: disable=broad-except, unused-variable # noqa F841;
        app.logger.error(err)
Example #5
0
def consume_nr(
        business: Business,
        filing: Filing,
        nr_num_path='/filing/incorporationApplication/nameRequest/nrNumber'):
    """Update the nr to a consumed state."""
    try:
        # skip this if none (nrNumber will not be available for numbered company)
        if nr_num := get_str(filing.filing_json, nr_num_path):

            namex_svc_url = current_app.config.get('NAMEX_API')
            token = AccountService.get_bearer_token()

            # Create an entity record
            data = json.dumps({'consume': {'corpNum': business.identifier}})
            rv = requests.patch(
                url=''.join([namex_svc_url, nr_num]),
                headers={
                    **AccountService.CONTENT_TYPE_JSON, 'Authorization':
                    AccountService.BEARER + token
                },
                data=data,
                timeout=AccountService.timeout)
            if not rv.status_code == HTTPStatus.OK:
                raise QueueException

            # remove the NR from the account
            if filing.temp_reg and (bootstrap :=
                                    RegistrationBootstrap.find_by_identifier(
                                        filing.temp_reg)):
                AccountService.delete_affiliation(bootstrap.account, nr_num)
def update_business_profile(business: Business, profile_info: Dict) -> Dict:
    """Set the legal type of the business."""
    if not business or not profile_info:
        return {'error': babel('Business and profile_info required.')}

    # contact phone is optional
    phone = profile_info.get('phone', '')

    error = {'error': 'Unknown handling'}
    if email := profile_info.get('email'):
        # assume the JSONSchema ensures it is a valid email format
        token = AccountService.get_bearer_token()
        account_svc_entity_url = current_app.config['ACCOUNT_SVC_ENTITY_URL']

        # Create an entity record
        data = json.dumps({
            'email': email,
            'phone': phone,
            'phoneExtension': ''
        })
        url = ''.join(
            [account_svc_entity_url, '/', business.identifier, '/contacts'])
        rv = requests.post(
            url=url,
            headers={
                **AccountService.CONTENT_TYPE_JSON, 'Authorization':
                AccountService.BEARER + token
            },
            data=data,
            timeout=AccountService.timeout)
        if rv.status_code in (HTTPStatus.OK, HTTPStatus.CREATED):
            error = None

        if rv.status_code == HTTPStatus.NOT_FOUND:
            error = {'error': 'No business profile found.'}

        if rv.status_code == HTTPStatus.METHOD_NOT_ALLOWED:
            error = {
                'error':
                'Service account missing privileges to update business profiles'
            }

        if rv.status_code == HTTPStatus.BAD_REQUEST and \
                'DATA_ALREADY_EXISTS' in rv.text:
            put = requests.put(
                url=''.join([account_svc_entity_url, '/',
                             business.identifier]),
                headers={
                    **AccountService.CONTENT_TYPE_JSON, 'Authorization':
                    AccountService.BEARER + token
                },
                data=data,
                timeout=AccountService.timeout)
            if put.status_code in (HTTPStatus.OK, HTTPStatus.CREATED):
                error = None
            else:
                error = {
                    'error': 'Unable to update existing business profile.'
                }
Example #7
0
def process_email(email_msg: dict, flask_app: Flask):  # pylint: disable=too-many-branches
    """Process the email contained in the submission."""
    if not flask_app:
        raise QueueException('Flask App not available.')

    with flask_app.app_context():
        logger.debug('Attempting to process email: %s', email_msg)
        token = AccountService.get_bearer_token()
        etype = email_msg.get('type', None)
        if etype and etype == 'bc.registry.names.request':
            option = email_msg.get('data', {}).get('request',
                                                   {}).get('option', None)
            if option and option in [
                    nr_notification.Option.BEFORE_EXPIRY.value,
                    nr_notification.Option.EXPIRED.value,
                    nr_notification.Option.RENEWAL.value,
                    nr_notification.Option.UPGRADE.value,
                    nr_notification.Option.REFUND.value
            ]:
                email = nr_notification.process(email_msg, option)
            else:
                email = name_request.process(email_msg)
            send_email(email, token)
        elif etype and etype == 'bc.registry.affiliation':
            email = affiliation_notification.process(email_msg, token)
            send_email(email, token)
        else:
            etype = email_msg['email']['type']
            option = email_msg['email']['option']
            if etype == 'businessNumber':
                email = bn_notification.process(email_msg['email'])
                send_email(email, token)
            elif etype == 'incorporationApplication' and option == 'mras':
                email = mras_notification.process(email_msg['email'])
                send_email(email, token)
            elif etype == 'annualReport' and option == 'reminder':
                email = ar_reminder_notification.process(
                    email_msg['email'], token)
                send_email(email, token)
            elif etype == 'dissolution':
                email = dissolution_notification.process(
                    email_msg['email'], token)
                send_email(email, token)
            elif etype in filing_notification.FILING_TYPE_CONVERTER.keys():
                if etype == 'annualReport' and option == Filing.Status.COMPLETED.value:
                    logger.debug('No email to send for: %s', email_msg)
                else:
                    email = filing_notification.process(
                        email_msg['email'], token)
                    if email:
                        send_email(email, token)
                    else:
                        # should only be if this was for a a coops filing
                        logger.debug('No email to send for: %s', email_msg)
            else:
                logger.debug('No email to send for: %s', email_msg)
Example #8
0
async def update_business_nos(application):  # pylint: disable=redefined-outer-name
    """Update the tax_ids for corps with new bn_15s."""
    try:
        # get updater-job token
        token = AccountService.get_bearer_token()

        # get identifiers with outstanding tax_ids
        application.logger.debug('Getting businesses with outstanding tax ids from legal api...')
        response = requests.get(
            application.config['LEGAL_URL'] + '/internal/tax_ids',
            headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'}
        )
        if response.status_code != 200:
            application.logger.error('legal-updater failed to get identifiers from legal-api.')
            raise Exception
        identifiers = response.json()

        if identifiers['identifiers']:
            # get tax ids that exist for above entities
            application.logger.debug(f'Getting tax ids for {identifiers["identifiers"]} from colin api...')
            response = requests.get(
                application.config['COLIN_URL'] + '/internal/tax_ids',
                json=identifiers,
                headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'}
            )
            if response.status_code != 200:
                application.logger.error('legal-updater failed to get tax_ids from colin-api.')
                raise Exception
            tax_ids = response.json()
            if tax_ids.keys():
                # update lear with new tax ids from colin
                application.logger.debug(f'Updating tax ids for {tax_ids.keys()} in lear...')
                response = requests.post(
                    application.config['LEGAL_URL'] + '/internal/tax_ids',
                    json=tax_ids,
                    headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'}
                )
                if response.status_code != 201:
                    application.logger.error('legal-updater failed to update tax_ids in lear.')
                    raise Exception

                await send_emails(tax_ids, application)

                application.logger.debug('Successfully updated tax ids in lear.')
            else:
                application.logger.debug('No tax ids in colin to update in lear.')
        else:
            application.logger.debug('No businesses in lear with outstanding tax ids.')

    except Exception as err:
        application.logger.error(err)
def run():
    """Get filings that haven't been synced with colin and send them to the colin-api."""
    application = create_app()
    corps_with_failed_filing = []
    with application.app_context():
        try:
            # get updater-job token
            token = AccountService.get_bearer_token()

            filings = get_filings(app=application)
            if not filings:
                # pylint: disable=no-member; false positive
                application.logger.debug(
                    'No completed filings to send to colin.')
            for filing in filings:
                filing_id = filing['filingId']
                identifier = filing['filing']['business']['identifier']
                if identifier in corps_with_failed_filing or is_test_coop(
                        identifier):
                    # pylint: disable=no-member; false positive
                    application.logger.debug(
                        f'Skipping filing {filing_id} for'
                        f' {filing["filing"]["business"]["identifier"]}.')
                else:
                    colin_ids = send_filing(app=application,
                                            filing=filing,
                                            filing_id=filing_id)
                    update = None
                    if colin_ids:
                        update = update_colin_id(app=application,
                                                 filing_id=filing_id,
                                                 colin_ids=colin_ids,
                                                 token=token)
                    if update:
                        # pylint: disable=no-member; false positive
                        application.logger.debug(
                            f'Successfully updated filing {filing_id}')
                    else:
                        corps_with_failed_filing.append(
                            filing['filing']['business']['identifier'])
                        # pylint: disable=no-member; false positive
                        application.logger.error(
                            f'Failed to update filing {filing_id} with colin event id.'
                        )

        except Exception as err:
            # pylint: disable=no-member; false positive
            application.logger.error(err)
Example #10
0
def process_email(email_msg: dict, flask_app: Flask):  # pylint: disable=too-many-branches
    """Process the email contained in the submission."""
    if not flask_app:
        raise QueueException('Flask App not available.')

    with flask_app.app_context():
        logger.debug('Attempting to process email: %s', email_msg)
        token = AccountService.get_bearer_token()
        etype = email_msg.get('type', None)
        if etype and etype == 'bc.registry.names.request':
            email = name_request.process(email_msg)
            send_email(email, token)
        else:
            etype = email_msg['email']['type']
            option = email_msg['email']['option']
            if etype == 'businessNumber':
                email = bn_notification.process(email_msg['email'])
                send_email(email, token)
            elif etype == 'incorporationApplication' and option == 'mras':
                email = mras_notification.process(email_msg['email'])
                send_email(email, token)
            elif etype in filing_notification.FILING_TYPE_CONVERTER.keys():
                if etype == 'annualReport' and option == Filing.Status.COMPLETED.value:
                    logger.debug('No email to send for: %s', email_msg)
                # Remove this when self serve alteration is implemented.
                elif etype == 'alteration' and option == Filing.Status.PAID.value:
                    logger.debug('No email to send for: %s', email_msg)
                else:
                    email = filing_notification.process(
                        email_msg['email'], token)
                    if email:
                        send_email(email, token)
                    else:
                        # should only be if this was for a a coops filing
                        logger.debug('No email to send for: %s', email_msg)
            else:
                logger.debug('No email to send for: %s', email_msg)
Example #11
0
def update_filings(application):  # pylint: disable=redefined-outer-name, too-many-branches
    """Get filings in colin that are not in lear and send them to lear."""
    successful_filings = 0
    failed_filing_events = []
    corps_with_failed_filing = []
    skipped_filings = []
    first_failed_id = None
    try:  # pylint: disable=too-many-nested-blocks
        # get updater-job token
        token = AccountService.get_bearer_token()

        # check if there are filings to send to legal
        manual_filings_info = check_for_manual_filings(application, token)
        max_event_id = 0

        if len(manual_filings_info) > 0:
            for event_info in manual_filings_info:
                # Make sure this coop has no outstanding filings that failed to be applied.
                # This ensures we don't apply filings out of order when one fails.
                if event_info['corp_num'] not in corps_with_failed_filing:
                    filing = get_filing(event_info, application)

                    # call legal api with filing
                    application.logger.debug(f'sending filing with event info: {event_info} to legal api.')
                    response = requests.post(
                        f'{application.config["LEGAL_URL"]}/{event_info["corp_num"]}/filings',
                        json=filing,
                        headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'}
                    )
                    if response.status_code != 201:
                        if not first_failed_id:
                            first_failed_id = event_info['event_id']
                        failed_filing_events.append(event_info)
                        corps_with_failed_filing.append(event_info['corp_num'])
                        application.logger.error(f'Legal failed to create filing for {event_info["corp_num"]}')
                    else:
                        # update max_event_id entered
                        successful_filings += 1
                        if int(event_info['event_id']) > max_event_id:
                            max_event_id = int(event_info['event_id'])
                else:
                    skipped_filings.append(event_info)
        else:
            application.logger.debug('0 filings updated in legal db.')

        application.logger.debug(f'successful filings: {successful_filings}')
        application.logger.debug(f'skipped filings due to related erred filings: {len(skipped_filings)}')
        application.logger.debug(f'failed filings: {len(failed_filing_events)}')
        application.logger.debug(f'failed filings event info: {failed_filing_events}')

        # if manually bringing across filings, set to first id so you don't skip any filings on the next run
        if SET_EVENTS_MANUALLY:
            first_failed_id = 102125621

        # if one of the events failed then save that id minus one so that the next run will try it again
        # this way failed filings wont get buried/forgotten after multiple runs
        if first_failed_id:
            max_event_id = first_failed_id - 1
        if max_event_id > 0:
            # update max_event_id in legal_db
            application.logger.debug('setting last_event_id in legal_db to {}'.format(max_event_id))
            response = requests.post(
                f'{application.config["LEGAL_URL"]}/internal/filings/colin_id/{max_event_id}',
                headers={'Content-Type': 'application/json', 'Authorization': f'Bearer {token}'}
            )
            if response.status_code != 201:
                application.logger.error(
                    f'Error adding {max_event_id} colin_last_update table in legal db {response.status_code}'
                )
            else:
                if dict(response.json())['maxId'] != max_event_id:
                    application.logger.error('Updated colin id is not max colin id in legal db.')
                else:
                    application.logger.debug('Successfully updated colin id in legal db.')

        else:
            application.logger.debug('colin_last_update not updated in legal db.')

    except Exception as err:
        application.logger.error(err)