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 historic_filings_exist(business_id): filings = Filing.get_filings_by_status(business_id, [Filing.Status.DRAFT.value]) for possible_historic in filings: if possible_historic.json['filing']['header']['date'] < '2019-03-08': return True return False
def test_get_filings_by_status_before_go_live_date(session, test_type, days, expected, status): """Assert that a filing can be retrieved by status.""" import copy uow = versioning_manager.unit_of_work(session) transaction = uow.create_transaction(session) business = factory_business('CP1234567') payment_token = '1000' ar = copy.deepcopy(ANNUAL_REPORT) go_live_date = datetime.date.fromisoformat(current_app.config.get('GO_LIVE_DATE')) filing_date = go_live_date + datetime.timedelta(days=days) filing = Filing() filing.filing_date = filing_date filing.business_id = business.id filing.filing_json = ar 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], go_live_date) assert eval(expected) # pylint: disable=eval-used; useful for parameterized tests if rv: assert rv[0].status == status
def get(identifier, filing_id=None): """Return a JSON object with meta information about the Service.""" business = Business.find_by_identifier(identifier) if not business: return jsonify({'message': f'{identifier} not found'}), HTTPStatus.NOT_FOUND if filing_id: rv = db.session.query(Business, Filing). \ filter(Business.id == Filing.business_id).\ filter(Business.identifier == identifier).\ filter(Filing.id == filing_id).\ one_or_none() if not rv: return jsonify({'message': f'{identifier} no filings found' }), HTTPStatus.NOT_FOUND if str(request.accept_mimetypes) == 'application/pdf': return legal_api.reports.get_pdf(rv[1]) return jsonify(rv[1].json) # Does it make sense to get a PDF of all filings? if str(request.accept_mimetypes) == 'application/pdf': return jsonify({'message': _('Cannot return a single PDF of multiple filing submissions.')}),\ HTTPStatus.NOT_ACCEPTABLE rv = [] filings = Filing.get_filings_by_status(business.id, [Filing.Status.COMPLETED.value]) for filing in filings: rv.append(filing.json) return jsonify(filings=rv)
def _process_colin_filing(identifier: str, filing: Filing, business: Business) -> Tuple[dict, int]: try: if not filing.colin_event_id: 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.save() return {'filing': {'id': filing.id}}, HTTPStatus.CREATED except KeyError: current_app.logger.error( 'Business:%s missing filing/header/colinId, unable to post to queue', identifier) return { 'errors': { 'message': 'missing filing/header/colinId' } }, 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 construct_task_list(business): """Return a task list object.""" tasks = [] order = 1 todo_start_year = 2019 # If no filings exist in legal API db this year will be used as the start year. pending_filings = Filing.get_filings_by_status(business.id, [Filing.Status.DRAFT.value, Filing.Status.PENDING.value, Filing.Status.ERROR.value]) for filing in pending_filings: task = {'task': filing.json, 'order': order, 'enabled': True} tasks.append(task) order += 1 annual_report_filings = Filing.get_filings_by_type(business.id, 'annualReport') if annual_report_filings: last_filing = annual_report_filings[0].filing_json todo_start_year = datetime.strptime(last_filing['filing']['annualReport']['annualGeneralMeetingDate'], '%Y-%m-%d').year + 1 if todo_start_year <= datetime.now().year: for todo_year in range(todo_start_year, datetime.now().year+1): enabled = not pending_filings and todo_year == todo_start_year tasks.append(TaskListResource.create_todo(business, todo_year, order, enabled)) order += 1 return tasks
def construct_task_list(business): """ Return all current pending tasks to do. First retrieves filings that are either drafts, or incomplete, then populate AR filings that have not been started for years that are due. Rules for AR filings: - Co-ops must file one AR per year. The next AR date must be AFTER the most recent AGM date. The calendar year of the filing is the first contiguous year following the last AGM date - Corporations must file one AR per year, on or after the anniversary of the founding date """ tasks = [] order = 1 check_agm = validations.annual_report.requires_agm(business) # If no filings exist in legal API db this year will be used as the start year. todo_start_date = (datetime( 2019, 1, 1)).date() if check_agm else business.next_anniversary.date() # Retrieve filings that are either incomplete, or drafts pending_filings = Filing.get_filings_by_status(business.id, [ Filing.Status.DRAFT.value, Filing.Status.PENDING.value, Filing.Status.ERROR.value ]) # Create a todo item for each pending filing for filing in pending_filings: task = {'task': filing.json, 'order': order, 'enabled': True} tasks.append(task) order += 1 # Retrieve all previous annual report filings. If there are existing AR filings, determine # the latest date of filing annual_report_filings = Filing.get_filings_by_type( business.id, 'annualReport') if annual_report_filings: if check_agm: last_ar_date = business.last_ar_date todo_start_date = (datetime(last_ar_date.year + 1, 1, 1)).date() else: todo_start_date = business.next_anniversary.date() start_year = todo_start_date.year while todo_start_date <= datetime.now().date(): enabled = not pending_filings and todo_start_date.year == start_year tasks.append( TaskListResource.create_todo(business, todo_start_date.year, order, enabled)) todo_start_date += datedelta.YEAR order += 1 return tasks
def history_needed(business: Business): """Check if there is history to load for this business.""" if business.legal_type != Business.LegalTypes.COOP.value: return False filings = Filing.get_filings_by_status(business.id, [Filing.Status.COMPLETED.value]) for possible_historic in filings: if possible_historic.json['filing']['header']['date'] < '2019-03-08': return False return True
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 test_get_filings_by_status__default_order(session): """Assert that a filing can be retrieved. by status and is returned in the default order. default order is submission_date, and then effective_date. """ # setup base_filing = copy.deepcopy(FILING_HEADER) base_filing['specialResolution'] = SPECIAL_RESOLUTION uow = versioning_manager.unit_of_work(session) business = factory_business('CP1234567') completion_date = datetime.datetime.utcnow().replace( tzinfo=datetime.timezone.utc) # setup - create multiple filings on the same day & time filing_ids = [] file_counter = -1 with freeze_time(completion_date): for i in range(0, 5): transaction = uow.create_transaction(session) payment_token = str(i) effective_date = f'200{i}-04-15T00:00:00+00:00' base_filing['filing']['header']['effectiveDate'] = effective_date filing = Filing() filing._filing_date = completion_date filing.business_id = business.id filing.filing_json = base_filing filing.effective_date = datetime.datetime.fromisoformat( effective_date) filing.payment_token = payment_token filing.transaction_id = transaction.id filing.payment_completion_date = completion_date filing.save() filing_ids.append(filing.id) file_counter += 1 # test rv = Filing.get_filings_by_status(business.id, [Filing.Status.COMPLETED.value]) # check assert rv # filings should be in newest to oldest effective date order for filing in rv: assert filing.id == filing_ids[file_counter] file_counter -= 1
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_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 = ANNUAL_REPORT 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 get(identifier, filing_id=None): """Return a JSON object with meta information about the Service.""" business = Business.find_by_identifier(identifier) if not business: return jsonify({'message': f'{identifier} not found'}), HTTPStatus.NOT_FOUND if filing_id: rv = db.session.query(Business, Filing). \ filter(Business.id == Filing.business_id).\ filter(Business.identifier == identifier).\ filter(Filing.id == filing_id).\ one_or_none() if not rv: return jsonify({'message': f'{identifier} no filings found' }), HTTPStatus.NOT_FOUND if str(request.accept_mimetypes) == 'application/pdf': return legal_api.reports.get_pdf(rv[1]) return jsonify(rv[1].json) # Does it make sense to get a PDF of all filings? if str(request.accept_mimetypes) == 'application/pdf': return 'Please specify a single filing', HTTPStatus.NOT_ACCEPTABLE rv = [] go_live_date = datetime.date.fromisoformat( current_app.config.get('GO_LIVE_DATE')) filings = Filing.get_filings_by_status(business.id, [Filing.Status.COMPLETED.value], go_live_date) for filing in filings: rv.append(filing.json) return jsonify(filings=rv)
def construct_task_list(business): # pylint: disable=too-many-locals; only 2 extra """ Return all current pending tasks to do. First retrieves filings that are either drafts, or incomplete, then populate AR filings that have not been started for years that are due. Rules for AR filings: - Co-ops must file one AR per year. The next AR date must be AFTER the most recent AGM date. The calendar year of the filing is the first contiguous year following the last AGM date - Corporations must file one AR per year, on or after the anniversary of the founding date """ tasks = [] order = 1 # Retrieve filings that are either incomplete, or drafts pending_filings = Filing.get_filings_by_status(business.id, [ Filing.Status.DRAFT.value, Filing.Status.PENDING.value, Filing.Status.PENDING_CORRECTION.value, Filing.Status.ERROR.value ]) # Create a todo item for each pending filing for filing in pending_filings: filing_json = filing.json if filing.payment_status_code == 'CREATED' and filing.payment_token: # get current pay details from pay-api try: headers = { 'Authorization': f'Bearer {jwt.get_token_auth_header()}', 'Content-Type': 'application/json' } pay_response = requests.get( url= f'{current_app.config.get("PAYMENT_SVC_URL")}/{filing.payment_token}', headers=headers) pay_details = { 'isPaymentActionRequired': pay_response.json().get('isPaymentActionRequired', False), 'paymentMethod': pay_response.json().get('paymentMethod', '') } filing_json['filing']['header'].update(pay_details) except (exceptions.ConnectionError, exceptions.Timeout) as err: current_app.logger.error( f'Payment connection failure for {business.identifier} task list. ', err) return 'pay_connection_error' task = {'task': filing_json, 'order': order, 'enabled': True} tasks.append(task) order += 1 # If this is the first calendar year since incorporation, there is no previous ar year. next_ar_year = (business.last_ar_year if business.last_ar_year else business.founding_date.year) + 1 start_date = (business.last_ar_date if business.last_ar_date else business.founding_date).date() # Checking for pending ar annual_report_filings = Filing.get_filings_by_type( business.id, 'annualReport') if annual_report_filings: # Consider each filing as each year and add to find next ar year next_ar_year += len(annual_report_filings) start_date = datetime(next_ar_year, 1, 1).date() ar_min_date, ar_max_date = validations.annual_report.get_ar_dates( business, start_date, next_ar_year) start_year = next_ar_year while ar_min_date <= datetime.utcnow().date(): # while next_ar_year <= datetime.utcnow().date(): enabled = not pending_filings and ar_min_date.year == start_year tasks.append( TaskListResource.create_todo(business, next_ar_year, ar_min_date, ar_max_date, order, enabled)) # Include all ar's to todo from last ar filing next_ar_year += 1 start_date = datetime(next_ar_year, 1, 1).date() ar_min_date, ar_max_date = validations.annual_report.get_ar_dates( business, start_date, next_ar_year) order += 1 return tasks
def construct_task_list(business): """ Return all current pending tasks to do. First retrieves filings that are either drafts, or incomplete, then populate AR filings that have not been started for years that are due. Rules for AR filings: - Co-ops must file one AR per year. The next AR date must be AFTER the most recent AGM date. The calendar year of the filing is the first contiguous year following the last AGM date - Corporations must file one AR per year, on or after the anniversary of the founding date """ tasks = [] order = 1 check_agm = validations.annual_report.requires_agm(business) # If no filings exist in legal API db (set after this line), use the business' next anniversary date todo_start_date = business.next_anniversary.date() # Retrieve filings that are either incomplete, or drafts pending_filings = Filing.get_filings_by_status(business.id, [ Filing.Status.DRAFT.value, Filing.Status.PENDING.value, Filing.Status.PENDING_CORRECTION.value, Filing.Status.ERROR.value ]) # Create a todo item for each pending filing for filing in pending_filings: task = {'task': filing.json, 'order': order, 'enabled': True} tasks.append(task) order += 1 last_ar_date = business.last_ar_date if check_agm: # If this is a CO-OP, set the start date to the first day of the year, since an AR filing # is available as of Jan/01 if last_ar_date: todo_start_date = (datetime(last_ar_date.year + 1, 1, 1)).date() else: # If this is the first calendar year since incorporation, there is no # previous ar date. Use the next anniversary year. todo_start_date = (datetime(todo_start_date.year, 1, 1)).date() # Retrieve all previous annual report filings. If there are existing AR filings, determine # the latest date of filing annual_report_filings = Filing.get_filings_by_type( business.id, 'annualReport') if annual_report_filings: # get last AR date from annualReportDate; if not present in json, try annualGeneralMeetingDate and # finally filing date last_ar_date = \ annual_report_filings[0].filing_json['filing']['annualReport'].get('annualReportDate', None) if not last_ar_date: last_ar_date = annual_report_filings[0].filing_json['filing']['annualReport']\ .get('annualGeneralMeetingDate', None) if not last_ar_date: last_ar_date = annual_report_filings[0].filing_date last_ar_date = datetime.fromisoformat(last_ar_date) if check_agm: todo_start_date = (datetime(last_ar_date.year + 1, 1, 1)).date() else: todo_start_date = (last_ar_date + datedelta.YEAR).date() start_year = todo_start_date.year while todo_start_date <= datetime.now().date(): enabled = not pending_filings and todo_start_date.year == start_year tasks.append( TaskListResource.create_todo(business, todo_start_date.year, order, enabled)) todo_start_date += datedelta.YEAR order += 1 return tasks
def get(identifier, filing_id=None): # pylint: disable=too-many-return-statements; # fix this while refactoring this whole module """Return a JSON object with meta information about the Service.""" if identifier.startswith('T'): q = db.session.query(Filing). \ filter(Filing.temp_reg == identifier) if filing_id: q = q.filter(Filing.id == filing_id) rv = q.one_or_none() if not rv: return jsonify({'message': f'{identifier} no filings found' }), HTTPStatus.NOT_FOUND if str(request.accept_mimetypes ) == 'application/pdf' and filing_id: if rv.filing_type == 'incorporationApplication': return legal_api.reports.get_pdf(rv, None) filing_json = rv.json filing_json['filing']['documents'] = document_meta.get_documents( filing_json) return jsonify(filing_json) business = Business.find_by_identifier(identifier) if not business: return jsonify(filings=[]), HTTPStatus.NOT_FOUND if filing_id: rv = db.session.query(Business, Filing). \ filter(Business.id == Filing.business_id).\ filter(Business.identifier == identifier).\ filter(Filing.id == filing_id).\ one_or_none() if not rv: return jsonify({'message': f'{identifier} no filings found' }), HTTPStatus.NOT_FOUND if str(request.accept_mimetypes) == 'application/pdf': report_type = request.args.get('type', None) if rv[1].filing_type == 'incorporationApplication': ListFilingResource._populate_business_info_to_filing( rv[1], business) return legal_api.reports.get_pdf(rv[1], report_type) return jsonify(rv[1].json) # Does it make sense to get a PDF of all filings? if str(request.accept_mimetypes) == 'application/pdf': return jsonify({'message': _('Cannot return a single PDF of multiple filing submissions.')}),\ HTTPStatus.NOT_ACCEPTABLE rv = [] filings = Filing.get_filings_by_status( business.id, [Filing.Status.COMPLETED.value, Filing.Status.PAID.value]) for filing in filings: filing_json = filing.json filing_json['filing']['documents'] = document_meta.get_documents( filing_json) rv.append(filing_json) return jsonify(filings=rv)