def test_get_filings_by_status(session): """Assert that a filing can be retrieved by status.""" uow = versioning_manager.unit_of_work(session) transaction = uow.create_transaction(session) business = factory_business('CP1234567') payment_token = '1000' filing = Filing() filing.business_id = business.id filing.filing_json = AR_FILING filing.payment_token = payment_token filing.transaction_id = transaction.id filing.payment_completion_date = datetime.datetime.utcnow() filing.save() rv = Filing.get_filings_by_status(business.id, [Filing.Status.COMPLETED.value]) assert rv assert rv[0].status == Filing.Status.COMPLETED.value
def test_filing_orm_delete_blocked_if_invoiced(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.payment_token = 'a token' 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_filing_block_orm_delete(session): """Assert that attempting to delete a filing will raise a BusinessException.""" from legal_api.exceptions import BusinessException 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() 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 create_filing(token, json_filing=None, business_id=None, filing_date=EPOCH_DATETIME, bootstrap_id: str = None): """Return a test filing.""" from legal_api.models import Filing filing = Filing() filing.payment_token = str(token) filing.filing_date = filing_date if json_filing: filing.filing_json = json_filing if business_id: filing.business_id = business_id if bootstrap_id: filing.temp_reg = bootstrap_id filing.save() return filing
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=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 factory_completed_filing(business, data_dict, filing_date=FROZEN_DATETIME, payment_token=None): """Create a completed filing.""" if not payment_token: payment_token = str(base64.urlsafe_b64encode(uuid.uuid4().bytes)).replace('=', '') with freeze_time(filing_date): filing = Filing() filing.business_id = business.id filing.filing_date = filing_date filing.filing_json = data_dict filing.save() uow = versioning_manager.unit_of_work(db.session) transaction = uow.create_transaction(db.session) filing.transaction_id = transaction.id filing.payment_token = payment_token filing.effective_date = filing_date filing.payment_completion_date = filing_date filing.save() return filing
def test_get_most_recent_filing_by_legal_type_db_field(session): """Assert that the most recent legal filing can be retrieved. Create 3 filings, find the 2 one by the type only. """ business = factory_business('CP1234567') uow = versioning_manager.unit_of_work(session) transaction = uow.create_transaction(session) # filing 1 effective_date = '2001-07-01T00:00:00+00:00' completion_date = datetime.datetime.fromisoformat(effective_date) base_filing = copy.deepcopy(ANNUAL_REPORT) base_filing['filing']['header']['effectiveDate'] = effective_date filing1 = Filing() filing1._filing_date = completion_date filing1.business_id = business.id filing1.filing_json = base_filing filing1.effective_date = datetime.datetime.fromisoformat(effective_date) filing1.payment_token = 'token' filing1.transaction_id = transaction.id filing1.payment_completion_date = completion_date filing1.save() # filing 2 <- target effective_date = '2002-07-01T00:00:00+00:00' completion_date = datetime.datetime.fromisoformat(effective_date) base_filing = copy.deepcopy(FILING_HEADER) base_filing['filing']['header']['effectiveDate'] = effective_date base_filing['filing']['header']['name'] = 'changeOfDirectors' base_filing['filing']['header']['availableOnPaperOnly'] = True filing2 = Filing() filing2._filing_date = completion_date filing2.business_id = business.id filing2.filing_json = base_filing filing2.effective_date = datetime.datetime.fromisoformat(effective_date) filing2.payment_token = 'token' filing2.transaction_id = transaction.id filing2.payment_completion_date = completion_date filing2.save() # filing 3 effective_date = '2003-07-01T00:00:00+00:00' completion_date = datetime.datetime.fromisoformat(effective_date) base_filing = copy.deepcopy(ANNUAL_REPORT) base_filing['filing']['header']['effectiveDate'] = effective_date filing3 = Filing() filing3._filing_date = completion_date filing3.business_id = business.id filing3.filing_json = base_filing filing3.effective_date = datetime.datetime.fromisoformat(effective_date) filing3.payment_token = 'token' filing3.transaction_id = transaction.id filing3.payment_completion_date = completion_date filing3.save() f = Filing.get_most_recent_legal_filing(business.id, 'changeOfDirectors') assert f.filing_type == 'changeOfDirectors' assert f.id == filing2.id
def test_put_incorporation_to_business_fails(session, client, jwt): """Assert that an incorporation cannot be PUT to the business endpoint.""" nr_number = 'NR 1234567' filing_json = copy.deepcopy(INCORPORATION_FILING_TEMPLATE) filing_json['filing']['incorporationApplication']['nameRequest'][ 'nrNumber'] = nr_number business = Business() business.identifier = nr_number business.save() filing = Filing() filing.filing_json = filing_json filing.business_id = business.id filing.save() # Post initial filing rv = client.put(f'/api/v1/businesses/{nr_number}', json=filing_json, headers=create_header(jwt, [STAFF_ROLE], nr_number)) assert HTTPStatus.METHOD_NOT_ALLOWED == rv.status_code
def test_conversion_bc_company_from_colin(app, session, legal_type): """Assert that an existing bc company(LTD, ULC, CCC) incorporation is loaded corrrectly.""" # setup identifier = 'BC0000001' colind_id = 1 filing = copy.deepcopy(CONVERSION_FILING_TEMPLATE) # Change the template to be LTD, ULC or CCC filing['filing']['business']['legalType'] = legal_type filing['filing']['business']['identifier'] = identifier filing['filing']['conversion']['nameRequest']['legalType'] = legal_type effective_date = datetime.utcnow() # Create the Filing object in the DB filing_rec = Filing(effective_date=effective_date, filing_json=filing) colin_event = ColinEventId() colin_event.colin_event_id = colind_id filing_rec.colin_event_ids.append(colin_event) # Override the state setting mechanism filing_rec.skip_status_listener = True filing_rec._status = 'PENDING' filing_rec.save() filing_meta = FilingMeta(application_date=effective_date) # test business, filing_rec = conversion.process(None, filing, filing_rec, filing_meta) # Assertions assert business.identifier == identifier assert business.founding_date.replace( tzinfo=None) == effective_date.replace(tzinfo=None) assert business.legal_type == filing['filing']['conversion'][ 'nameRequest']['legalType'] assert business.legal_name == business.identifier[2:] + ' B.C. LTD.' assert len(business.offices.all() ) == 2 # One office is created in create_business method. assert len(business.share_classes.all()) == 2 assert len(business.party_roles.all()) == 3
def test_is_corrected_filing(session): """Assert that corrected filing has the isCorrected flag set. Assert linkage is set from parent to child and otherway. """ from legal_api.models import Filing # setup filing1 = Filing() filing1.filing_json = ANNUAL_REPORT filing1.save() b = factory_business('CP1234567') filing2 = factory_completed_filing(b, CORRECTION_AR) filing1.parent_filing = filing2 filing1.save() # test assert filing1.json['filing']['header']['isCorrected'] is True assert filing1.json['filing']['header']['isCorrectionPending'] is False assert filing2.json['filing']['header']['affectedFilings'] is not None assert filing2.json['filing']['header']['affectedFilings'][0] == filing1.id
def test_put_draft_incorporation_filing(session, client, jwt): """Assert that an incorporation filing can be put (updated) to filings endpoint.""" nr_number = 'NR 1234567' filing_json = copy.deepcopy(INCORPORATION_FILING_TEMPLATE) filing_json['filing']['incorporationApplication']['nameRequest'][ 'nrNumber'] = nr_number business = Business() business.identifier = nr_number business.save() filing = Filing() filing.filing_json = filing_json filing.business_id = business.id filing.save() # PUT updated filing rv = client.put( f'/api/v1/businesses/{nr_number}/filings/{filing.id}?draft=true', json=filing_json, headers=create_header(jwt, [STAFF_ROLE], nr_number)) assert HTTPStatus.ACCEPTED == rv.status_code
def test_linked_not_correction(session): """Assert that if a filing has a parent that is not a correction, the isCorrected flag is not set.""" from legal_api.models import Filing # setup filing1 = Filing() filing1.filing_json = ANNUAL_REPORT filing1.save() f = copy.deepcopy(FILING_HEADER) f['filing']['changeOfDirectors'] = CHANGE_OF_DIRECTORS filing2 = Filing() filing2.filing_json = f filing2.save() filing1.parent_filing = filing2 filing1.save() # test assert filing1.json['filing']['header']['isCorrected'] is False assert filing2.json['filing']['header']['affectedFilings'] is not None
def _create_invoice(business: Business, filing: Filing, filing_types: list, user_jwt: JwtManager) \ -> Tuple[int, dict, int]: """Create the invoice for the filing submission. Returns: { int: the paymentToken (id), or None dict: a dict of errors, or None int: the HTTPStatus error code, or None } """ payment_svc_url = current_app.config.get('PAYMENT_SVC_URL') mailing_address = business.mailing_address.one_or_none() payload = { 'paymentInfo': { 'methodOfPayment': 'CC' }, 'businessInfo': { 'businessIdentifier': f'{business.identifier}', 'corpType': f'{business.identifier[:-7]}', 'businessName': f'{business.legal_name}', 'contactInfo': { 'city': mailing_address.city, 'postalCode': mailing_address.postal_code, 'province': mailing_address.region, 'addressLine1': mailing_address.street, 'country': mailing_address.country } }, 'filingInfo': { 'filingTypes': filing_types } } if user_jwt.validate_roles([STAFF_ROLE]): routing_slip_number = get_str(filing.filing_json, 'filing/header/routingSlipNumber') if routing_slip_number: payload['accountInfo'] = {'routingSlip': routing_slip_number} try: token = user_jwt.get_token_auth_header() headers = {'Authorization': 'Bearer ' + token} rv = requests.post(url=payment_svc_url, json=payload, headers=headers, timeout=20.0) except (exceptions.ConnectionError, exceptions.Timeout) as err: current_app.logger.error( f'Payment connection failure for {business.identifier}: filing:{filing.id}', err) return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED if rv.status_code == HTTPStatus.OK or rv.status_code == HTTPStatus.CREATED: pid = rv.json().get('id') filing.payment_token = pid filing.save() return None, None return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED
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_json = json_input if user.username == 'coops-updater-job': try: filing.filing_date = datetime.datetime.fromisoformat( filing.filing_json['filing']['header']['date']) filing.colin_event_id = filing.filing_json['filing'][ 'header']['colinId'] except KeyError: current_app.logger.error( 'Business:%s missing filing/header values, unable to save', business.identifier) return None, None, { 'message': 'missing filing/header values' }, HTTPStatus.BAD_REQUEST else: filing.filing_date = datetime.datetime.utcnow() filing.save() except BusinessException as err: return None, None, {'error': err.error}, err.status_code return business, filing, None, None
def _create_invoice(business: Business, filing: Filing, user_jwt: JwtManager) \ -> Tuple[int, dict, int]: """Create the invoice for the filing submission. Returns: { int: the paymentToken (id), or None dict: a dict of errors, or None int: the HTTPStatus error code, or None } """ payment_svc_url = current_app.config.get('PAYMENT_SVC_URL') filing_types = [] for k in filing.filing_json['filing'].keys(): if Filing.FILINGS.get(k, None): filing_types.append( {'filing_type_code': Filing.FILINGS[k].get('code')}) mailing_address = business.mailing_address.one_or_none() payload = { 'payment_info': { 'method_of_payment': 'CC' }, 'business_info': { 'business_identifier': f'{business.identifier}', 'corp_type': f'{business.identifier[:-7]}', 'business_name': f'{business.legal_name}', 'contact_info': { 'city': mailing_address.city, 'postal_code': mailing_address.postal_code, 'province': mailing_address.region, 'address_line_1': mailing_address.street, 'country': mailing_address.country } }, 'filing_info': { 'filing_types': filing_types } } try: token = user_jwt.get_token_auth_header() headers = {'Authorization': 'Bearer ' + token} rv = requests.post(url=payment_svc_url, json=payload, headers=headers, timeout=5.0) except (exceptions.ConnectionError, exceptions.Timeout) as err: current_app.logger.error( f'Payment connection failure for {business.identifier}: filing:{filing.id}', err) return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED if rv.status_code == HTTPStatus.OK or rv.status_code == HTTPStatus.CREATED: pid = rv.json().get('id') filing.payment_token = pid filing.save() return None, None return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED
def _save_filing( client_request: LocalProxy, # pylint: disable=too-many-return-statements,too-many-branches business_identifier: str, user: User, filing_id: int ) -> Tuple[Union[Business, RegistrationBootstrap], 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 @TODO refactor to a set of single putpose routines } """ 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 if business_identifier.startswith('T'): # bootstrap filing bootstrap = RegistrationBootstrap.find_by_identifier( business_identifier) business = None if not bootstrap: return None, None, { 'message': f'{business_identifier} not found' }, HTTPStatus.NOT_FOUND if client_request.method == 'PUT': rv = db.session.query(Filing). \ filter(Filing.temp_reg == 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 else: filing = Filing() filing.temp_reg = bootstrap.identifier if not json_input['filing'].get('business'): json_input['filing']['business'] = {} json_input['filing']['business'][ 'identifier'] = bootstrap.identifier else: # regular filing for a business 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_json = json_input filing.source = filing.filing_json['filing']['header'].get( 'source', Filing.Source.LEAR.value) if filing.source == Filing.Source.COLIN.value: try: filing.filing_date = datetime.datetime.fromisoformat( filing.filing_json['filing']['header']['date']) for colin_id in filing.filing_json['filing']['header'][ 'colinIds']: colin_event_id = ColinEventId() colin_event_id.colin_event_id = colin_id filing.colin_event_ids.append(colin_event_id) except KeyError: current_app.logger.error( 'Business:%s missing filing/header values, unable to save', business.identifier) return None, None, { 'message': 'missing filing/header values' }, HTTPStatus.BAD_REQUEST else: filing.filing_date = datetime.datetime.utcnow() # for any legal type, set effective date as set in json; otherwise leave as default filing.effective_date = \ datetime.datetime.fromisoformat(filing.filing_json['filing']['header']['effectiveDate']) \ if filing.filing_json['filing']['header'].get('effectiveDate', None) else datetime.datetime.utcnow() filing.save() except BusinessException as err: return None, None, {'error': err.error}, err.status_code return business or bootstrap, filing, None, None
def _create_invoice(business: Business, # pylint: disable=too-many-locals filing: Filing, filing_types: list, user_jwt: JwtManager, payment_account_id: str = None) \ -> Tuple[int, dict, int]: """Create the invoice for the filing submission. Returns: { int: the paymentToken (id), or None dict: a dict of errors, or None int: the HTTPStatus error code, or None } """ payment_svc_url = current_app.config.get('PAYMENT_SVC_URL') if filing.filing_type == Filing.FILINGS[ 'incorporationApplication'].get('name'): mailing_address = Address.create_address( filing.json['filing']['incorporationApplication']['offices'] ['registeredOffice']['mailingAddress']) corp_type = filing.json['filing']['business'].get( 'legalType', Business.LegalTypes.BCOMP.value) try: business.legal_name = filing.json['filing'][ 'incorporationApplication']['nameRequest']['legalName'] except KeyError: business.legal_name = business.identifier else: mailing_address = business.mailing_address.one_or_none() corp_type = business.legal_type if business.legal_type else \ filing.json['filing']['business'].get('legalType') payload = { 'businessInfo': { 'businessIdentifier': f'{business.identifier}', 'corpType': f'{corp_type}', 'businessName': f'{business.legal_name}', 'contactInfo': { 'city': mailing_address.city, 'postalCode': mailing_address.postal_code, 'province': mailing_address.region, 'addressLine1': mailing_address.street, 'country': mailing_address.country } }, 'filingInfo': { 'filingTypes': filing_types } } folio_number = filing.json['filing']['header'].get('folioNumber', None) if folio_number: payload['filingInfo']['folioNumber'] = folio_number if user_jwt.validate_roles([STAFF_ROLE]) or \ user_jwt.validate_roles([SYSTEM_ROLE]): account_info = {} routing_slip_number = get_str(filing.filing_json, 'filing/header/routingSlipNumber') if routing_slip_number: account_info['routingSlip'] = routing_slip_number bcol_account_number = get_str(filing.filing_json, 'filing/header/bcolAccountNumber') if bcol_account_number: account_info['bcolAccountNumber'] = bcol_account_number dat_number = get_str(filing.filing_json, 'filing/header/datNumber') if dat_number: account_info['datNumber'] = dat_number if account_info: payload['accountInfo'] = account_info try: token = user_jwt.get_token_auth_header() headers = { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' } rv = requests.post(url=payment_svc_url, json=payload, headers=headers, timeout=20.0) except (exceptions.ConnectionError, exceptions.Timeout) as err: current_app.logger.error( f'Payment connection failure for {business.identifier}: filing:{filing.id}', err) return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED if rv.status_code in (HTTPStatus.OK, HTTPStatus.CREATED): pid = rv.json().get('id') filing.payment_token = pid filing.payment_status_code = rv.json().get('statusCode', '') filing.payment_account = payment_account_id filing.save() return { 'isPaymentActionRequired': rv.json().get('isPaymentActionRequired', False) }, HTTPStatus.CREATED if rv.status_code == HTTPStatus.BAD_REQUEST: # Set payment error type used to retrieve error messages from pay-api error_type = rv.json().get('type') filing.payment_status_code = error_type filing.save() return { 'payment_error_type': error_type, 'message': rv.json().get('detail') }, HTTPStatus.PAYMENT_REQUIRED return { 'message': 'unable to create invoice for payment.' }, HTTPStatus.PAYMENT_REQUIRED