def _process_colin_filing(identifier: str, filing: Filing, business: Business) -> Tuple[dict, int]: try: if not filing.colin_event_ids: raise KeyError if not ListFilingResource._is_before_epoch_filing( filing.filing_json, business): payload = {'filing': {'id': filing.id}} queue.publish_json(payload) else: epoch_filing = Filing.get_filings_by_status( business_id=business.id, status=[Filing.Status.EPOCH.value]) filing.transaction_id = epoch_filing[0].transaction_id filing.set_processed() filing.save() return {'filing': {'id': filing.id}}, HTTPStatus.CREATED except KeyError: current_app.logger.error( 'Business:%s missing filing/header/colinIds, unable to post to queue', identifier) return { 'errors': { 'message': 'missing filing/header/colinIds' } }, HTTPStatus.BAD_REQUEST except Exception as err: # pylint: disable=broad-except; final catch current_app.logger.error( 'Business:%s unable to post to queue, err=%s', identifier, err) return { 'errors': { 'message': 'unable to publish for post processing' } }, HTTPStatus.BAD_REQUEST
def create_filing(token, json_filing=None, business_id=None): """Return a test filing.""" from legal_api.models import Filing filing = Filing() filing.payment_token = str(token) filing.filing_date = EPOCH_DATETIME if json_filing: filing.filing_json = json_filing if business_id: filing.business_id = business_id filing.save() return filing
def _save_incorporation_filing(incorporation_body, client_request, business_id=None): """Create or update an incorporation filing.""" # Check that there is a JSON filing if not incorporation_body: return None, {'message': f'No filing json data in body of post for incorporation'}, \ HTTPStatus.BAD_REQUEST temp_corp_num = incorporation_body['filing'][ 'incorporationApplication']['nameRequest']['nrNumber'] # temp_corp_num = business_id # If this is an update to an incorporation filing, a temporary business identifier is passed in if business_id: business = Business.find_by_identifier(business_id) if not business: return None, {'message': f'No incorporation filing exists for id {business_id}'}, \ HTTPStatus.BAD_REQUEST else: # Ensure there are no current businesses with the NR/random identifier business = Business.find_by_identifier(temp_corp_num) if business: return None, {'message': f'Incorporation filing for {temp_corp_num} already exists'}, \ HTTPStatus.BAD_REQUEST # Create an empty business record, to be updated by the filer business = Business() business.identifier = temp_corp_num business.save() # Ensure the business identifier matches the NR in the filing err = validate(business, incorporation_body) if err: return None, err.msg, err.code filing = Filing.get_filings_by_type(business.id, 'incorporationApplication') # There can only be zero or one incorporation filings, if there are none, this is an # initial request for incorporation. Create and insert a filing. if not filing: filing = Filing() filing.business_id = business.id elif len(filing) > 1: return None, { 'message': 'more than one incorporation filing found for corp' }, HTTPStatus.BAD_REQUEST else: filing = filing[0] filing.filing_json = incorporation_body filing.save() return filing, None, (HTTPStatus.CREATED if (client_request.method == 'POST') else HTTPStatus.ACCEPTED)
def _save_filing(client_request: LocalProxy, business_identifier: str, user: User, filing_id: int) -> Tuple[Business, Filing, dict, int]: """Save the filing to the ledger. If not successful, a dict of errors is returned. Returns: { Business: business model object found for the identifier provided Filing: filing model object for the submitted filing dict: a dict of errors int: the HTTPStatus error code } """ json_input = client_request.get_json() if not json_input: return None, None, {'message': f'No filing json data in body of post for {business_identifier}.'}, \ HTTPStatus.BAD_REQUEST business = Business.find_by_identifier(business_identifier) if not business: return None, None, {'message': f'{business_identifier} not found'}, HTTPStatus.NOT_FOUND if client_request.method == 'PUT': rv = db.session.query(Business, Filing). \ filter(Business.id == Filing.business_id). \ filter(Business.identifier == business_identifier). \ filter(Filing.id == filing_id). \ one_or_none() if not rv: return None, None, {'message': f'{business_identifier} no filings found'}, HTTPStatus.NOT_FOUND filing = rv[1] else: filing = Filing() filing.business_id = business.id try: filing.submitter_id = user.id filing.filing_date = datetime.datetime.utcnow() filing.filing_json = json_input filing.save() except BusinessException as err: return None, None, {'error': err.error}, err.status_code return business, filing, None, None
def test_ia_status(session, app, status, number_of_docs): """Assert that IA + NOA + Certificate documents are returned for a COMPLETED IA filing.""" document_meta = DocumentMetaService() with app.app_context(): filing = { 'filing': { 'header': { 'filingId': 12356, 'status': status, 'name': 'incorporationApplication', 'inColinOnly': False, 'availableOnPaperOnly': False, 'effectiveDate': FILING_DATE, 'date': FILING_DATE }, 'business': { 'identifier': 'T12345678' }, 'incorporationApplication': { 'nameRequest': { 'legalType': Business.LegalTypes.BCOMP.value } } } } with patch.object(Filing, 'find_by_id', return_value=Filing()): documents = document_meta.get_documents(filing) assert len(documents) == number_of_docs if number_of_docs: assert documents[0]['type'] == 'REPORT' assert documents[0]['reportType'] is None assert documents[0]['filingId'] == 12356 assert documents[0]['title'] == 'Incorporation Application' assert documents[0][ 'filename'] == 'T12345678 - Incorporation Application - 2020-07-14.pdf' assert documents[1]['type'] == 'REPORT' assert documents[1]['reportType'] == 'noa' assert documents[1]['filingId'] == 12356 assert documents[1]['title'] == 'Notice of Articles' assert documents[1][ 'filename'] == 'T12345678 - Notice of Articles - 2020-07-14.pdf' assert documents[2]['type'] == 'REPORT' assert documents[2]['reportType'] == 'certificate' assert documents[2]['filingId'] == 12356 assert documents[2]['title'] == 'Certificate' assert documents[2][ 'filename'] == 'T12345678 - Certificate - 2020-07-14.pdf'
def test_submitter_info(session): user = factory_user('idir/staff-person') filing = Filing() filing.submitter_roles = 'STAFF' filing.submitter_id = user.id filing.save() assert filing.id
def test_invoiced_filing_raises_exception_when_changed(session): """Assert a BusinessException is raised if a locked filing is altered.""" # locked filing = Filing() filing.payment_token = 'payment_token' filing.save() with pytest.raises(BusinessException): filing.payment_token = 'should raise exception'
def test_get_filing_by_payment_token(session): """Assert that a filing can be retrieved by a unique payment token.""" payment_token = '1000' filing = Filing() filing.filing_json = ANNUAL_REPORT filing.payment_token = payment_token filing.save() rv = Filing.get_filing_by_payment_token(payment_token) assert rv assert rv.payment_token == payment_token
def test_get_registrar_for_a_filing(session): """Assert that the registrar effective on that date is returned.""" b = factory_business('CP1234567') filing = Filing() filing.business_id = b.id filing.filing_date = datetime.datetime(2012, 6, 6) filing.effective_date = datetime.datetime(2012, 6, 6) filing.filing_data = ANNUAL_REPORT filing.save() registrar_info = RegistrarInfo.get_registrar_info(filing.effective_date) assert registrar_info['startDate'] assert registrar_info['endDate'] assert registrar_info['signature'] assert registrar_info['name'] == 'ANGELO COCCO' assert registrar_info['title'] == 'A/Registrar of Companies'
def _is_before_epoch_filing(filing_json: str, business: Business): if not business or not filing_json: return False epoch_filing = Filing.get_filings_by_status( business_id=business.id, status=[Filing.Status.EPOCH.value]) if len(epoch_filing) != 1: current_app.logger.error( 'Business:%s either none or too many epoch filings', business.identifier) return False filing_date = datetime.datetime.fromisoformat( filing_json['filing']['header']['date']).replace( tzinfo=datetime.timezone.utc) return filing_date < epoch_filing[0].filing_date
def factory_filing(business, data_dict, filing_date=FROZEN_DATETIME, filing_type=None): """Create a filing.""" filing = Filing() filing.business_id = business.id filing.filing_date = filing_date filing.filing_json = data_dict if filing_type: filing._filing_type = filing_type try: filing.save() except Exception as err: print(err) return filing
def test_delete_bootstrap_draft_filing(client, jwt, session): """Assert that a draft IA filing can be retrieved.""" account_id = 26 identifier, filing_id = setup_bootstrap_ia_minimal(jwt, session, client, account_id) # # Test that we can get the filing # rv = client.delete(f'/api/v1/businesses/{identifier}/filings/{filing_id}', headers=create_header(jwt, [STAFF_ROLE], None)) assert rv.status_code == HTTPStatus.OK assert not Filing.find_by_id(filing_id) assert not RegistrationBootstrap.find_by_identifier(identifier)
def test_add_payment_completion_date_after_payment(session): """Assert that the json can be added in the same session that a paymentToken was applied.""" filing = Filing() filing.filing_date = EPOCH_DATETIME filing.save() filing.payment_token = 'payment token' filing.filing_json = ANNUAL_REPORT # sanity check starting position assert filing.json assert filing.status == Filing.Status.PENDING.value filing.payment_completion_date = EPOCH_DATETIME print(filing.status) assert filing.status == Filing.Status.COMPLETED.value
def test_changing_uninvoiced_saved_filing_is_unlocked(session): """Assert that saving an un-invoiced filing is still unlocked.""" # should succeed filing = Filing() filing.filing_date = EPOCH_DATETIME filing.filing_json = ANNUAL_REPORT assert not filing.locked filing.save() assert not filing.locked
def delete(identifier, filing_id=None): # pylint: disable=too-many-branches """Delete a filing from the business.""" if not filing_id: return ({ 'message': _('No filing id provided for:') + identifier }, HTTPStatus.BAD_REQUEST) # check authorization if not authorized(identifier, jwt, action=['edit']): return jsonify({'message': _('You are not authorized to delete a filing for:') + identifier}),\ HTTPStatus.UNAUTHORIZED if identifier.startswith('T'): filing = Filing.get_temp_reg_filing(identifier, filing_id) else: filing = Business.get_filing_by_id(identifier, filing_id) if not filing: return jsonify({'message': _('Filing Not Found.')}), HTTPStatus.NOT_FOUND if filing.deletion_locked: # should not be deleted return ListFilingResource._create_deletion_locked_response( identifier, filing) try: ListFilingResource._delete_from_minio(filing) filing.delete() except BusinessException as err: return jsonify({'errors': [ { 'error': err.error }, ]}), err.status_code if identifier.startswith('T'): bootstrap = RegistrationBootstrap.find_by_identifier(identifier) if bootstrap: deregister_status = RegistrationBootstrapService.deregister_bootstrap( bootstrap) delete_status = RegistrationBootstrapService.delete_bootstrap( bootstrap) if deregister_status != HTTPStatus.OK or delete_status != HTTPStatus.OK: current_app.logger.error( 'Unable to deregister and delete temp reg:', identifier) return jsonify({'message': _('Filing deleted.')}), HTTPStatus.OK
def create_filing(token=None, filing_json=None, business_id=None, filing_date=EPOCH_DATETIME, bootstrap_id: str = None): """Return a test filing.""" filing = Filing() if token: filing.payment_token = str(token) filing.filing_date = filing_date if filing_json: filing.filing_json = filing_json if business_id: filing.business_id = business_id if bootstrap_id: filing.temp_reg = bootstrap_id filing.save() return filing
def test_save_filing_with_colin_id(session): """Assert that saving a filing with a colin event id is set to paid.""" from legal_api.models import Filing # setup filing = Filing() filing.filing_json = ANNUAL_REPORT user = User.create_from_jwt_token({ 'username': '******', 'iss': 'test', 'sub': 'test' }) filing.submitter_id = user.id filing.save() # test assert filing.status == Filing.Status.DRAFT.value assert filing.source == Filing.Source.COLIN.value filing.colin_event_id = 1234 filing.save() assert filing.status == Filing.Status.PAID.value
def test_minimal_filing_json(session): """Assert that a minimal filing can be created.""" b = factory_business('CP1234567') data = {'filing': 'not a real filing, fail validation'} filing = Filing() filing.business_id = b.id filing.filing_date = datetime.datetime.utcnow() filing.filing_data = json.dumps(data) filing.save() assert filing.id is not None
def get(status=None): """Get filings by status formatted in json.""" pending_filings = [] filings = [] if status is None: pending_filings = Filing.get_completed_filings_for_colin() for filing in pending_filings: filing_json = filing.filing_json business = Business.find_by_internal_id(filing.business_id) if filing_json and filing.filing_type != 'lear_epoch' and \ (filing.filing_type != 'correction' or business.legal_type != business.LegalTypes.COOP.value): filing_json['filingId'] = filing.id filing_json['filing']['header'][ 'learEffectiveDate'] = filing.effective_date.isoformat( ) if not filing_json['filing']['business'].get('legalName'): business = Business.find_by_internal_id( filing.business_id) filing_json['filing']['business'][ 'legalName'] = business.legal_name if filing.filing_type == 'correction': colin_ids = \ ColinEventId.get_by_filing_id(filing_json['filing']['correction']['correctedFilingId']) if not colin_ids: continue filing_json['filing']['correction'][ 'correctedFilingColinId'] = colin_ids[ 0] # should only be 1 filings.append(filing_json) return jsonify(filings), HTTPStatus.OK pending_filings = Filing.get_all_filings_by_status(status) for filing in pending_filings: filings.append(filing.json) return jsonify(filings), HTTPStatus.OK
def test_filing_orm_delete_blocked_if_completed(session): """Assert that attempting to delete a filing will raise a BusinessException.""" from legal_api.exceptions import BusinessException uow = versioning_manager.unit_of_work(session) transaction = uow.create_transaction(session) b = factory_business('CP1234567') filing = Filing() filing.business_id = b.id filing.filing_date = datetime.datetime.utcnow() filing.filing_json = ANNUAL_REPORT filing.payment_token = 'a token' filing.payment_completion_date = datetime.datetime.utcnow() filing.transaction_id = transaction.id filing.save() with pytest.raises(BusinessException) as excinfo: session.delete(filing) session.commit() assert excinfo.value.status_code == HTTPStatus.FORBIDDEN assert excinfo.value.error == 'Deletion not allowed.'
def test_incorporation_filing_process_correction(app, session): """Assert that the incorporation correction is correctly populated to model objects.""" # setup next_corp_num = 'BC0001095' with patch.object(incorporation_filing, 'get_next_corp_num', return_value=next_corp_num) as mock_get_next_corp_num: filing = copy.deepcopy(INCORPORATION_FILING_TEMPLATE) create_filing('123', filing) effective_date = datetime.utcnow() filing_rec = Filing(effective_date=effective_date, filing_json=filing) filing_meta = FilingMeta(application_date=filing_rec.effective_date) # test business, filing_rec, filing_meta = incorporation_filing.process(None, filing, filing_rec, filing_meta) # Assertions assert business.identifier == next_corp_num assert business.founding_date == effective_date assert business.legal_type == filing['filing']['incorporationApplication']['nameRequest']['legalType'] assert business.legal_name == business.identifier[2:] + ' B.C. LTD.' assert len(business.share_classes.all()) == 2 assert len(business.offices.all()) == 2 # One office is created in create_business method. mock_get_next_corp_num.assert_called_with(filing['filing']['incorporationApplication']['nameRequest']['legalType']) correction_filing = copy.deepcopy(CORRECTION_INCORPORATION) correction_filing['filing']['incorporationApplication']['nameTranslations'] = [{'name': 'A5 Ltd.'}] del correction_filing['filing']['incorporationApplication']['shareStructure']['shareClasses'][1] corrected_filing_rec = Filing(effective_date=effective_date, filing_json=correction_filing) corrected_filing_meta = FilingMeta(application_date=corrected_filing_rec.effective_date) corrected_business, corrected_filing_rec, corrected_filing_meta =\ incorporation_filing.process(business, correction_filing, corrected_filing_rec, corrected_filing_meta) assert corrected_business.identifier == next_corp_num assert corrected_business.legal_name == \ correction_filing['filing']['incorporationApplication']['nameRequest']['legalName'] assert len(corrected_business.share_classes.all()) == 1
def test_updating_payment_token_fails(session): """Assert that a payment token cannot be updated.""" filing = Filing() filing.payment_token = 'payment token' filing.save() with pytest.raises(BusinessException) as excinfo: filing.payment_token = 'payment token' assert excinfo.value.status_code == HTTPStatus.FORBIDDEN
def get_filing_info(filing_id: str) -> (Filing, dict, dict, str, str): """Get filing info for the email.""" filing = Filing.find_by_id(filing_id) business = (filing.json)['filing']['business'] filing_date = datetime.fromisoformat(filing.filing_date.isoformat()) leg_tmz_filing_date = LegislationDatetime.as_legislation_timezone(filing_date) hour = leg_tmz_filing_date.strftime('%I').lstrip('0') leg_tmz_filing_date = leg_tmz_filing_date.strftime(f'%B %d, %Y {hour}:%M %p Pacific Time') effective_date = datetime.fromisoformat(filing.effective_date.isoformat()) leg_tmz_effective_date = LegislationDatetime.as_legislation_timezone(effective_date) hour = leg_tmz_effective_date.strftime('%I').lstrip('0') leg_tmz_effective_date = leg_tmz_effective_date.strftime(f'%B %d, %Y {hour}:%M %p Pacific Time') return filing, business, leg_tmz_filing_date, leg_tmz_effective_date
def test_add_json_and_payment_after_saved_filing(session): """Assert that the json can be added in the same session that a paymentToken was applied.""" filing = Filing() filing.filing_date = EPOCH_DATETIME filing.save() # sanity check starting value assert filing.status == Filing.Status.DRAFT.value filing.payment_token = 'payment token' filing.filing_json = ANNUAL_REPORT assert filing.json assert filing.status == Filing.Status.PENDING.value
def _process_colin_filing(identifier: str, filing: Filing, business: Business) -> Tuple[dict, int]: try: if not filing.colin_event_ids: raise KeyError if (epoch_filing := Filing.get_filings_by_status(business_id=business.id, status=[Filing.Status.EPOCH.value]) ) and \ ListFilingResource._is_before_epoch_filing(filing.filing_json, business): filing.transaction_id = epoch_filing[0].transaction_id filing.set_processed() filing.save() else:
def validate_effective_date(business: Business, cod: Dict) -> List: """Return an error or warning message based on the effective date validation rules. Rules: (text from the BA rules document) - The effective date of change cannot be in the future. - The effective date cannot be a date prior to their Incorporation Date. - The effective date of change cannot be a date that is farther in the past than a previous COD filing (standalone or AR). - The effective date can be the same effective date as another COD filing (standalone or AR). If this is the case: - COD filing that was filed most recently is the most current director information. """ msg = [] # get effective datetime string from filing try: effective_datetime_str = cod['filing']['header']['effectiveDate'] except KeyError: return {'error': babel('No effective date provided.')} # convert string to datetime try: effective_datetime_utc = datetime.fromisoformat(effective_datetime_str) except ValueError: return {'error': babel('Invalid ISO format for effective date.')} # check if effective datetime is in the future if effective_datetime_utc > datetime.utcnow(): msg.append({'error': babel('Filing cannot have a future effective date.')}) # convert to legislation timezone and then get date only effective_date_leg = LegislationDatetime.as_legislation_timezone(effective_datetime_utc).date() # check if effective date is before their incorporation date founding_date_leg = LegislationDatetime.as_legislation_timezone(business.founding_date).date() if effective_date_leg < founding_date_leg: msg.append({'error': babel('Effective date cannot be before businesses founding date.')}) # check if effective date is before their most recent COD or AR date last_cod_filing = Filing.get_most_recent_legal_filing(business.id, Filing.FILINGS['changeOfDirectors']['name']) if last_cod_filing: last_cod_date_leg = LegislationDatetime.as_legislation_timezone(last_cod_filing.effective_date).date() if effective_date_leg < last_cod_date_leg: msg.append({'error': babel('Effective date cannot be before another Change of Director filing.')}) return msg
def get(identifier): """Return a JSON object with meta information about the Service.""" business = Business.find_by_identifier(identifier) is_nr = identifier.startswith('NR') # Check if this is a NR if is_nr: # Fetch NR Data nr_response = namex.query_nr_number(identifier) # Validate NR data validation_result = namex.validate_nr(nr_response.json()) # Return error if the NR is not consumable (invalid) if not validation_result['is_consumable']: return jsonify({ 'message': f'{identifier} is invalid', 'validation': validation_result }), HTTPStatus.FORBIDDEN if not business: # Create Incorporate using NR to-do item if is_nr: rv = [] rv.append( TaskListResource.create_incorporate_nr_todo( nr_response.json(), 1, True)) # business does not exist and not an nr so return empty task list else: rv = [] else: rv = TaskListResource.construct_task_list(business) if not rv and is_nr: paid_completed_filings = Filing.get_filings_by_status( business.id, [Filing.Status.PAID.value, Filing.Status.COMPLETED.value]) # Append NR todo if there are no tasks and PAID or COMPLETED filings if not paid_completed_filings: rv.append( TaskListResource.create_incorporate_nr_todo( nr_response.json(), 1, True)) elif rv == 'pay_connection_error': return { 'message': 'Failed to get payment details for a filing. Please try again later.' }, HTTPStatus.SERVICE_UNAVAILABLE return jsonify(tasks=rv)
def test_filing_orm_delete_allowed_for_in_progress_filing(session): """Assert that attempting to delete a filing will raise a BusinessException.""" from legal_api.exceptions import BusinessException b = factory_business('CP1234567') filing = Filing() filing.business_id = b.id filing.filing_date = datetime.datetime.utcnow() filing.filing_json = ANNUAL_REPORT filing.save() with not_raises(BusinessException): session.delete(filing) session.commit()
def test_ia_completed_bcomp(session, app): """Assert that IA + NOA + Certificate documents are returned for a COMPLETED IA filing when business is a BCOMP.""" document_meta = DocumentMetaService() factory_business(identifier='BC1234567', entity_type=Business.LegalTypes.BCOMP.value) with app.app_context(): filing = { 'filing': { 'header': { 'filingId': 12356, 'status': 'COMPLETED', 'name': 'incorporationApplication', 'inColinOnly': False, 'availableOnPaperOnly': False, 'effectiveDate': FILING_DATE, 'date': FILING_DATE }, 'business': { 'identifier': 'BC1234567' } } } with patch.object(Filing, 'find_by_id', return_value=Filing()): documents = document_meta.get_documents(filing) assert len(documents) == 3 assert documents[0]['type'] == 'REPORT' assert documents[0]['reportType'] is None assert documents[0]['filingId'] == 12356 assert documents[0]['title'] == 'Incorporation Application' assert documents[0][ 'filename'] == 'BC1234567 - Incorporation Application - 2020-07-14.pdf' assert documents[1]['type'] == 'REPORT' assert documents[1]['reportType'] == 'noa' assert documents[1]['filingId'] == 12356 assert documents[1]['title'] == NOA_TITLE assert documents[1]['filename'] == NOA_FILENAME assert documents[2]['type'] == 'REPORT' assert documents[2]['reportType'] == 'certificate' assert documents[2]['filingId'] == 12356 assert documents[2]['title'] == 'Certificate' assert documents[2][ 'filename'] == 'BC1234567 - Certificate - 2020-07-14.pdf'
def _set_registrar_info(self, filing): if filing.get('correction'): original_filing = Filing.find_by_id( filing.get('correction').get('correctedFilingId')) original_registrar = { **RegistrarInfo.get_registrar_info(original_filing.effective_date) } filing['registrarInfo'] = original_registrar current_registrar = { **RegistrarInfo.get_registrar_info(self._filing.effective_date) } if original_registrar['name'] != current_registrar['name']: filing['currentRegistrarInfo'] = current_registrar else: filing['registrarInfo'] = { **RegistrarInfo.get_registrar_info(self._filing.effective_date) }