def get(payment_id): try: payment = PaymentDAO.query.get(payment_id) # Find the existing name request nr_model = RequestDAO.query.get(payment.nrId) if not nr_model: # Should this be a 400 or 404... hmmm return jsonify(message='{nr_id} not found'.format( nr_id=nr_model.id)), 400 receipt_response = get_receipt(payment.payment_token) if receipt_response is None: return jsonify(message=MSG_NOT_FOUND ), 404 # TODO: What if we have a record? response = make_response(receipt_response, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def post(self): try: # Creates a new NameRequestService, validates the app config, and sets the request data to the NameRequestService instance self.initialize() nr_svc = self.nr_service # Create a new DRAFT name request nr_model = nr_svc.create_name_request() # Handle state changes # Use update_nr as it enforces the State change pattern # Transition the DRAFT to the state specified in the request: # eg. one of [State.DRAFT, State.COND_RESERVE, State.RESERVED] nr_model = self.update_nr(nr_model, nr_svc.request_state_code, self.handle_nr_create) # Record the event EventRecorder.record(nr_svc.user, Event.POST, nr_model, nr_svc.request_data) # Update Solr - note that we don't save DRAFT name requests to Solr for corp entities only if nr_model.stateCd in [State.COND_RESERVE, State.RESERVED] and \ nr_model.entity_type_cd in \ ['CR', 'UL', 'BC', 'CP', 'PA', 'XCR', 'XUL', 'XCP', 'CC', 'FI', 'XCR', 'XUL', 'XCP']: self.create_solr_nr_doc(SOLR_CORE, nr_model) current_app.logger.debug(nr_model.json()) response_data = nr_model.json() # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = nr_svc.current_state_actions return jsonify(response_data), 201 except NameRequestException as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, repr(err), 500)
def delete(self, nr_id, payment_id): try: # Find the existing name request nr_model = RequestDAO.query.get(nr_id) if not nr_model: return jsonify(message=f'No NR found with id: {nr_id}.'), 404 # Find the existing payment record payment = PaymentDAO.find_by_payment_token(payment_id) if not payment: return jsonify(message=f'No payment record with id: {payment_id}.'), 404 # check payment record state is CREATED current_payment_state = payment.payment_status_code if current_payment_state != PaymentStatusCode.CREATED.value: return jsonify(message=f'Unable to cancel a payment record in {current_payment_state} state.'), 400 try: # cancelling may change with refactor cancel_payment(payment.payment_token) payment.payment_status_code = PaymentState.CANCELLED.value payment.save_to_db() response_data = nr_model.json() # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = get_nr_state_actions(nr_model.stateCd, nr_model) return jsonify(response_data), 200 except PaymentServiceError as err: # should only get here if there was a conflict (payment went through before cancel happened) return handle_exception(err, err.message, 409) except Exception as err: return handle_exception(err, repr(err), 500)
def post(self, corp_num): try: authenticated, token = get_client_credentials( SBC_SVC_AUTH_URL, SBC_SVC_AUTH_CLIENT_ID, SBC_SVC_CLIENT_SECRET) if not authenticated: raise ColinServiceException( message=MSG_CLIENT_CREDENTIALS_REQ_FAILED) # Get the profile print('\nCalling COLIN API using [corp_num: {corp_num}]'.format( corp_num=corp_num)) colin_url = COLIN_SVC_URL.format(corp_num=corp_num) headers = { # 'x-api-key': COLIN_SVC_API_KEY, # 'Accept': 'application/xml' 'Authorization': 'Bearer ' + token } print(colin_url) print(repr(headers)) response = requests.get(colin_url, headers=headers) content = json.loads(response.text) if response.status_code != 200: return jsonify(content.get('message')), response.status_code return jsonify(content), response.status_code except ColinServiceException as err: return handle_exception(err, err.message, err.status_code) except Exception as err: return handle_exception(err, 'Internal Server Error', 500)
def get(self, nr_id): try: nr_model = RequestDAO.query.get(nr_id) nr_payments = nr_model.payments.all() response_data = [] # Wrap our payment for payment in nr_payments: payment_response = get_payment(payment.payment_token) receipts = payment_response.receipts # Wrap the response, providing info from both the SBC Pay response and the payment we created response_data.append({ 'id': payment.id, 'nrId': payment.nrId, 'token': payment.payment_token, 'statusCode': payment.payment_status_code, 'action': payment.payment_action, 'completionDate': payment.payment_completion_date, 'payment': payment.as_dict(), 'sbcPayment': payment_response.as_dict(), 'receipts': list(map(lambda r: map_receipt(r), receipts)) }) return jsonify(response_data), 200 except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def patch(self, nr_id, action): """ Roll back a Name Request to a usable state in case of a frontend error. :param nr_id: :param action: :return: """ try: if not full_access_to_name_request(request): return { "message": "You do not have access to this NameRequest." }, 403 # Find the existing name request nr_model = Request.query.get(nr_id) # Creates a new NameRequestService, validates the app config, and sets request_data to the NameRequestService instance self.initialize() nr_svc = self.nr_service nr_svc.nr_num = nr_model.nrNum nr_svc.nr_id = nr_model.id # This could be moved out, but it's fine here for now def validate_patch_request(data): # TODO: Validate the data payload # Use the NR model state as the default, as the state change may not be included in the PATCH request is_valid = False msg = '' # This handles updates if the NR state is 'patchable' if NameRequestRollbackActions.has_value(action): is_valid = True else: msg = 'Invalid rollback action' return is_valid, msg is_valid_patch, validation_msg = validate_patch_request( self.request_data) validation_msg = validation_msg if not len( validation_msg) > 0 else 'Invalid request for PATCH' if not is_valid_patch: raise InvalidInputError(message=validation_msg) # This handles updates if the NR state is 'patchable' nr_model = self.handle_patch_rollback(nr_model, action) current_app.logger.debug(nr_model.json()) response_data = nr_model.json() # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = nr_svc.current_state_actions return jsonify(response_data), 200 except NameRequestException as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, repr(err), 500)
def put(self, nr_id): """ NOT used for Existing Name Request updates that only change the Name Request. Use 'patch' instead. State changes handled include state changes to [DRAFT, COND_RESERVE, RESERVED, COND_RESERVE to CONDITIONAL, RESERVED to APPROVED] :param nr_id: :return: """ try: # Find the existing name request nr_model = Request.query.get(nr_id) # Creates a new NameRequestService, validates the app config, and sets request_data to the NameRequestService instance self.initialize() nr_svc = self.nr_service nr_svc.nr_num = nr_model.nrNum nr_svc.nr_id = nr_model.id valid_update_states = [ State.DRAFT, State.COND_RESERVE, State.RESERVED, State.PENDING_PAYMENT ] # This could be moved out, but it's fine here for now def validate_put_request(data): is_valid = False msg = '' if data.get('stateCd') in valid_update_states: is_valid = True return is_valid, msg is_valid_put, validation_msg = validate_put_request( self.request_data) validation_msg = validation_msg if not len( validation_msg) > 0 else 'Invalid request for PUT' if not is_valid_put: raise InvalidInputError(message=validation_msg) if nr_model.stateCd in valid_update_states: nr_model = self.update_nr(nr_model, nr_model.stateCd, self.handle_nr_update) # Record the event EventRecorder.record(nr_svc.user, Event.PUT, nr_model, nr_svc.request_data) current_app.logger.debug(nr_model.json()) response_data = nr_model.json() # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = nr_svc.current_state_actions return jsonify(response_data), 200 except NameRequestException as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, repr(err), 500)
def get(self, nr_id): try: nr_model = RequestDAO.query.get(nr_id) nr_payments = nr_model.payments.all() response_data = [] # Wrap our payment for payment in nr_payments: payment_response = get_payment(payment.payment_token) receipts = payment_response.receipts if not receipts and payment_response.statusCode == PaymentState.APPROVED.value: # generate temp receipts for approved payments current_app.logger.debug('adding temporary receipt details.') receipts = [ { 'id': payment.payment_token, 'receiptAmount': None, 'receiptDate': None, 'receiptNumber': 'Pending' } ] payment_response.receipts = receipts response_data.append({ 'id': payment.id, 'nrId': payment.nrId, 'token': payment.payment_token, 'statusCode': payment.payment_status_code, 'action': payment.payment_action, 'completionDate': payment.payment_completion_date, 'payment': payment.as_dict(), 'sbcPayment': payment_response.as_dict(), 'receipts': receipts }) else: # Wrap the response, providing info from both the SBC Pay response and the payment we created response_data.append({ 'id': payment.id, 'nrId': payment.nrId, 'token': payment.payment_token, 'statusCode': payment.payment_status_code, 'action': payment.payment_action, 'completionDate': payment.payment_completion_date, 'payment': payment.as_dict(), 'sbcPayment': payment_response.as_dict(), 'receipts': list(map(lambda r: map_receipt(r), receipts)) }) return jsonify(response_data), 200 except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def post(nr_num): try: # TODO: Validate NR string format # if not RequestDAO.validNRFormat(nr_num): # return jsonify(message='NR number is not in a valid format \'NR 9999999\''), 400 nr_draft = RequestDAO.find_by_nr(nr_num) if not nr_draft: # Should this be a 400 or 404... hmmm return jsonify(message='{nr_num} not found'.format(nr_num=nr_num)), 400 json_input = request.get_json() if not json_input: return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 elif isinstance(json_input, str): json_input = json.loads(json_input) # Grab the info we need off the request payment_info = json_input.get('paymentInfo') filing_info = json_input.get('filingInfo') business_info = json_input.get('businessInfo') # Create our payment request req = PaymentRequest( payment_info=payment_info, filing_info=filing_info, business_info=business_info ) payment_response = create_payment(req) if not payment_response: raise PaymentServiceError(message=MSG_ERROR_CREATING_RESOURCE) if payment_response and payment_response.status_code == PaymentStatusCode.CREATED.value: # Save the payment info to Postgres payment = PaymentDAO() payment.nrId = nr_draft.id payment.payment_token = str(payment_response.id) payment.payment_completion_date = payment_response.created_on payment.payment_status_code = PaymentState.CREATED.value payment.save_to_db() data = jsonify(payment_response.to_dict()) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, 500) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(self, nr_id): return {"message": "Not Implemented"}, 503 try: nr_model = Request.query.get(nr_id) if nr_model.requestTypeCd and (not nr_model.entity_type_cd or not nr_model.request_action_cd): # If requestTypeCd is set, but a request_entity (entity_type_cd) and a request_action (request_action_cd) # are not, use get_mapped_entity_and_action_code to map the values from the requestTypeCd entity_type, request_action = get_mapped_entity_and_action_code( nr_model.requestTypeCd) nr_model.entity_type_cd = entity_type nr_model.request_action_cd = request_action response_data = nr_model.json() # If draft, get the wait time and oldest queued request if nr_model.stateCd == 'DRAFT': service = WaitTimeStatsService() wait_time_response = service.get_waiting_time_dict() response_data.update(wait_time_response) # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = get_nr_state_actions( nr_model.stateCd, nr_model) return jsonify(response_data), 200 except Exception as err: current_app.logger.debug(repr(err)) return handle_exception(err, 'Error retrieving the NR.', 500)
def post(payment_id): try: payment = PaymentDAO.query.get(payment_id) # Find the existing name request nr_model = RequestDAO.query.get(payment.nrId) if not nr_model: # Should this be a 400 or 404... hmmm return jsonify(message='{nr_id} not found'.format( nr_id=nr_model.id)), 400 receipt_info = get_receipt(payment.payment_token) name_choice = RequestDAO.find_name_by_choice(nr_model.id, 1) if not name_choice: return jsonify( message='Could not find name choice for {nr_id}'.format( nr_id=nr_model.id)), 400 tz_aware_payment_completion_date = payment.payment_completion_date.replace( tzinfo=timezone('UTC')) localized_payment_completion_date = tz_aware_payment_completion_date.astimezone( timezone('US/Pacific')) receipt_req = ReceiptRequest( corpName=name_choice.name, filingDateTime=localized_payment_completion_date.strftime( '%B %-d, %Y at %-I:%M %P Pacific time')) receipt_response = generate_receipt(payment.payment_token, receipt_req) if not receipt_response: return jsonify(message=MSG_NOT_FOUND), 404 return send_file( receipt_response, as_attachment=True, attachment_filename='payment-receipt-{id}.pdf'.format( id=receipt_info.get('receiptNumber'))) except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(self, nr_id, payment_id): try: # Find the existing name request nr_model = RequestDAO.query.get(nr_id) if not nr_model: # Should this be a 400 or 404... hmmm return jsonify(message='{nr_id} not found'.format( nr_id=nr_id)), 400 payment_id = int(clean_url_path_param(payment_id)) payment = PaymentDAO.query.get(payment_id) payment_response = get_payment(payment.payment_token) receipts = payment_response.receipts # Wrap the response, providing info from both the SBC Pay response and the payment we created data = jsonify({ 'id': payment.id, 'nrId': payment.nrId, 'token': payment.payment_token, 'statusCode': payment.payment_status_code, 'completionDate': payment.payment_completion_date, 'payment': payment.as_dict(), 'sbcPayment': payment_response.as_dict(), 'receipts': list(map(lambda r: map_receipt(r), receipts)) }) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def put(self, nr_id, payment_id): try: # Find the existing name request nr_model = RequestDAO.query.get(nr_id) if not nr_model: # Should this be a 400 or 404... hmmm return jsonify(message='{nr_id} not found'.format( nr_id=nr_id)), 400 payment_id = clean_url_path_param(payment_id) json_input = request.get_json() if not json_input: return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 # Grab the info we need off the request payment_info = json_input.get('paymentInfo') filing_info = json_input.get('filingInfo') business_info = json_input.get('businessInfo') # Update our payment request req = PaymentRequest(payment_info=payment_info, filing_info=filing_info, business_info=business_info) payment_response = update_payment(payment_id, req) if not payment_response: raise PaymentServiceError(message=MSG_ERROR_CREATING_RESOURCE) data = jsonify(payment_response.to_dict()) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(payment_id): try: payment = PaymentDAO.query.get(payment_id) # Find the existing name request nr_model = RequestDAO.query.get(payment.nrId) if not nr_model: # Should this be a 400 or 404... hmmm return jsonify(message='{nr_id} not found'.format( nr_id=payment.nrId)), 400 payment_response = get_payment(payment.payment_token) # TODO: Make sure we pick the right one... use the first choice corp_name = nr_model.names.all()[0].name req = PaymentReceiptInput( corp_name=corp_name, business_number=None, recognition_date_time=None, filing_identifier=None, filing_date_time=payment_response.created_on, file_name=None) receipt_response = get_receipt(payment.payment_token, req) if not receipt_response: return jsonify(message=MSG_NOT_FOUND ), 404 # TODO: What if we have a record? return send_file(receipt_response, mimetype='application/pdf', as_attachment=True) except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(payment_identifier): try: payment_identifier = clean_url_path_param(payment_identifier) payment = get_payment(payment_identifier) if not payment: return jsonify(message=MSG_NOT_FOUND), 404 data = jsonify(payment) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(payment_identifier): try: payment_identifier = clean_url_path_param(payment_identifier) invoices = get_invoices(payment_identifier) if not invoices: return jsonify(message=MSG_NOT_FOUND), 404 data = jsonify(invoices.to_dict()) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, 500) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def post(): try: json_input = request.get_json() if not json_input: return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 corp_type = json_input.get( 'corp_type', 'NRO' ) # TODO: Maybe use a constant for this, it's the default corp_type, and I am not aware of a situation where it would be changed... filing_type_code = json_input.get( 'filing_type_code' ) # TODO: Maybe throw an error if these don't exist, we can't really get fees without them jurisdiction = json_input.get( 'jurisdiction', None ) # TODO: Maybe throw an error if these don't exist, we can't really get fees without them date = json_input.get('date', None) priority = json_input.get('priority', None) headers = json_input.get('headers', None) # Params are snake_case for this POST req = CalculateFeesRequest(corp_type=corp_type, filing_type_code=filing_type_code, jurisdiction=jurisdiction, date=date, priority=priority, headers=headers) fees = calculate_fees(req) data = jsonify(fees) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(self, nr_id): try: nr_model = RequestDAO.query.get(nr_id) nr_payments = nr_model.payments.all() response_data = [] # Wrap our payment for payment in nr_payments: payment_response = get_payment(payment.payment_token) # TODO: Replace this when we're ready! invoices_response = [] # get_invoices(payment.payment_token) if not payment_response: return None # Don't blow up just because we can't get the invoices if not invoices_response or isinstance(invoices_response, list) is False: invoices_response = [] # Wrap the response, providing info from both the SBC Pay response and the payment we created response_data.append({ 'id': payment.id, 'nrId': payment.nrId, 'token': payment.payment_token, 'statusCode': payment.payment_status_code, 'completionDate': payment.payment_completion_date, 'invoices': invoices_response, 'payment': payment.as_dict(), 'sbcPayment': payment_response.to_dict() }) return jsonify(response_data), 200 except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def post(payment_identifier): try: payment_identifier = clean_url_path_param(payment_identifier) json_input = request.get_json() if not json_input: return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 corp_name = json_input.get('corpName', None) business_number = json_input.get('businessNumber', None) recognition_date_time = json_input.get('recognitionDateTime', None) filing_identifier = json_input.get('filingIdentifier', None) filing_date_time = json_input.get('filingDateTime', None) file_name = json_input.get('fileName', None) req = PaymentReceiptInput( corp_name=corp_name, business_number=business_number, recognition_date_time=recognition_date_time, filing_identifier=filing_identifier, filing_date_time=filing_date_time, file_name=file_name ) receipt = get_receipt(payment_identifier, req) if not receipt: return jsonify(message=MSG_NOT_FOUND), 404 return send_file(receipt, mimetype='application/pdf', as_attachment=True) except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, 500) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(payment_identifier, invoice_id): try: payment_identifier = clean_url_path_param(payment_identifier) invoice_id = invoice_id if invoice_id else None invoice = get_invoice(payment_identifier, invoice_id) if not invoice: return jsonify(message=MSG_NOT_FOUND), 404 data = jsonify(invoice.to_dict()) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def post(): try: json_input = request.get_json() if not json_input: return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 corp_type = json_input.get('corp_type') filing_type_code = json_input.get('filing_type_code') jurisdiction = json_input.get('jurisdiction', None) date = json_input.get('date', None) priority = json_input.get('priority', None) # Params are snake_case for this POST # Response data is also snake_case req = CalculateFeesRequest( corp_type=corp_type, filing_type_code=filing_type_code, jurisdiction=jurisdiction, date=date, priority=priority ) fees = calculate_fees(req) if not fees: raise SBCPaymentError(message=MSG_ERROR_CREATING_RESOURCE) data = jsonify(fees.to_dict()) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, 500) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def put(payment_identifier): try: payment_identifier = clean_url_path_param(payment_identifier) json_input = request.get_json() if not json_input: return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 # Grab the info we need off the request payment_info = json_input.get('paymentInfo') filing_info = json_input.get('filingInfo') business_info = json_input.get('businessInfo') # Update our payment request req = PaymentRequest( payment_info=payment_info, filing_info=filing_info, business_info=business_info ) payment_response = update_payment(payment_identifier, req) if not payment_response: raise PaymentServiceError(message=MSG_ERROR_CREATING_RESOURCE) data = jsonify(payment_response.to_dict()) response = make_response(data, 200) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, 500) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get(self, nr_id): try: if not full_access_to_name_request(request): return { "message": "You do not have access to this NameRequest." }, 403 nr_model = Request.query.get(nr_id) if not nr_model: return jsonify(message='{nr_id} not found'.format( nr_id=nr_model.id)), HTTPStatus.NOT_FOUND if nr_model.stateCd not in [ State.APPROVED, State.CONDITIONAL, State.CONSUMED, State.EXPIRED, State.REJECTED ]: return jsonify(message='Invalid NR state'.format( nr_id=nr_model.id)), HTTPStatus.BAD_REQUEST authenticated, token = ReportResource._get_service_client_token() if not authenticated: return jsonify(message='Error in authentication'.format(nr_id=nr_model.id)),\ HTTPStatus.INTERNAL_SERVER_ERROR headers = { 'Authorization': 'Bearer {}'.format(token), 'Content-Type': 'application/json' } data = { 'reportName': ReportResource._get_report_filename(nr_model), 'template': "'" + base64.b64encode(bytes(self._get_template(), 'utf-8')).decode() + "'", 'templateVars': ReportResource._get_template_data(nr_model) } response = requests.post( url=current_app.config.get('REPORT_SVC_URL'), headers=headers, data=json.dumps(data)) if response.status_code != HTTPStatus.OK: return jsonify( message=str(response.content)), response.status_code return response.content, response.status_code except Exception as err: return handle_exception(err, 'Error retrieving the report.', 500)
def get(): try: service = WaitTimeStatsService() response = service.get_statistics() if not response: raise ApiServiceException( message='WaitTimeStatsService did not return a result') return jsonify(response), HTTPStatus.OK except ValueError as err: return jsonify('Wait time stats not found: ' + repr(err)), 200 except ApiServiceException as err: return handle_exception(err, err.message, 400) except Exception as err: return jsonify('Internal Server Error\n' + repr(err)), 500
def get(self, nr_id): try: nr_model = Request.query.get(nr_id) if nr_model.requestTypeCd and (not nr_model.entity_type_cd or not nr_model.request_action_cd): # If requestTypeCd is set, but a request_entity (entity_type_cd) and a request_action (request_action_cd) # are not, use get_mapped_entity_and_action_code to map the values from the requestTypeCd entity_type, request_action = get_mapped_entity_and_action_code(nr_model.requestTypeCd) nr_model.entity_type_cd = entity_type nr_model.request_action_cd = request_action response_data = nr_model.json() # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = get_nr_state_actions(nr_model.stateCd, nr_model) return jsonify(response_data), 200 except Exception as err: return handle_exception(err, 'Error retrieving the NR.', 500)
def get(self, province, corp_num): try: # Get the jurisdiction print( 'Calling MRAS Jurisdictions API using [corp_num: {corp_num}]'. format(corp_num=corp_num)) mras_url = MRAS_SVC_PROFILE_JUR_URL.format(profile_id=corp_num) headers = { 'x-api-key': MRAS_SVC_API_KEY, 'Accept': 'application/xml' } print(mras_url) print(repr(headers)) response = requests.get(mras_url, headers=headers) if not response.status_code == 200: mras_errors = load_xml_response_content( response, './/mras_error') mras_error = { 'error_code': mras_errors[0].find('error_code').text, 'internal_error_code': mras_errors[0].find('internal_error_code').text, 'internal_error_message': mras_errors[0].find('internal_error_message').text } raise MrasServiceException( mras_error=mras_error, message='Error retrieving MRAS profile jurisdictions') jurisdiction_id_els = load_xml_response_content( response, './/mras:JurisdictionID') jurisdiction_ids = [j.text for j in jurisdiction_id_els ] # All we care about are the codes / IDs if province not in jurisdiction_ids: return jsonify( message='Invalid request, province jurisdiction is incorrect' ), HTTPStatus.BAD_REQUEST else: print('Valid jurisdiction IDs') print(repr(jurisdiction_ids)) # Get the profile print( '\nCalling MRAS Profile API using [corp_num: {corp_num}], [province: {province}]' .format(corp_num=corp_num, province=province)) mras_url = MRAS_SVC_PROFILE_URL.format( profile_id=corp_num, source_jurisdiction_id=province) # headers = { # 'x-api-key': MRAS_SVC_API_KEY, # 'Accept': 'application/xml' # } headers = { 'x-api-key': MRAS_SVC_API_KEY, 'Accept': 'application/json' } print(mras_url) print(repr(headers)) response = requests.get(mras_url, headers=headers) # Return the auth response if an error occurs if not response.status_code == HTTPStatus.OK: return jsonify({ 'error': 'No profile found for the jurisdiction, registration number pair.' }), HTTPStatus.NOT_FOUND # mras_errors = load_xml_response_content(response, './/mras_error') # mras_error = { # 'error_code': mras_errors[0].find('error_code').text, # 'internal_error_code': mras_errors[0].find('internal_error_code').text, # 'internal_error_message': mras_errors[0].find('internal_error_message').text # } # raise MrasServiceException(mras_error=mras_error) # Just return true or false, the profile either exists or it doesn't return jsonify(response.json()), HTTPStatus.OK except MrasServiceException as err: return handle_exception(err, err.message, err.error_code) except Exception as err: return handle_exception(err, 'Internal Server Error', HTTPStatus.INTERNAL_SERVER_ERROR)
def post(self, nr_id, payment_action=NameRequestActions.COMPLETE.value): """ At this point, the Name Request will still be using a TEMPORARY NR number. Confirming the payment on the frontend triggers this endpoint. Here, we: - Save the request to NRO which gives us a real NR. - Create the payment via SBC Pay. - If payment creation is successful, create a corresponding payment record in our system. :param nr_id: :param payment_action: :return: """ try: # Find the existing name request nr_model = RequestDAO.query.get(nr_id) if not nr_model: # Should this be a 400 or 404... hmmm return jsonify(message='Name Request {nr_id} not found'.format( nr_id=nr_id)), 400 if not payment_action: return jsonify( message='Invalid payment action, {action} not found'. format(action=payment_action)), 400 valid_payment_action = payment_action in [ NameRequestActions.COMPLETE.value, NameRequestActions.UPGRADE.value, NameRequestActions.REAPPLY.value ] if not valid_payment_action: return jsonify( message='Invalid payment action [{action}]'.format( action=payment_action)), 400 # We only handle payments if the NR is in the following states valid_payment_states = [ State.DRAFT, State.COND_RESERVE, State.RESERVED, State.CONDITIONAL, State.APPROVED ] valid_nr_state = nr_model.stateCd in valid_payment_states if not valid_nr_state: return jsonify(message='Invalid NR state'.format( action=payment_action)), 400 if valid_payment_action and valid_nr_state: if payment_action in [NameRequestActions.COMPLETE.value]: # Save the record to NRO, which swaps the NR-L Number for a real NR update_solr = True nr_model = self.add_records_to_network_services( nr_model, update_solr) json_input = request.get_json() payment_request = {} if not json_input: # return jsonify(message=MSG_BAD_REQUEST_NO_JSON_BODY), 400 # Grab the data from the NR, if it exists payment_request = build_payment_request(nr_model) elif isinstance(json_input, dict): payment_request = merge_payment_request(nr_model, json_input) elif isinstance(json_input, str): payment_request = merge_payment_request( nr_model, json.loads(json_input)) # Grab the info we need off the request payment_info = payment_request.get('paymentInfo') filing_info = payment_request.get('filingInfo') business_info = payment_request.get('businessInfo') # Create our payment request req = PaymentRequest(payment_info=payment_info, filing_info=filing_info, business_info=business_info) payment_response = create_payment(req) if not payment_response: raise PaymentServiceError(message=MSG_ERROR_CREATING_RESOURCE) if payment_response and payment_response.status_code == PaymentStatusCode.CREATED.value: # Save the payment info to Postgres payment = PaymentDAO() payment.nrId = nr_model.id payment.payment_token = str(payment_response.id) payment.payment_completion_date = payment_response.created_on payment.payment_status_code = PaymentState.CREATED.value payment.save_to_db() # Wrap the response, providing info from both the SBC Pay response and the payment we created data = jsonify({ 'id': payment.id, 'nrId': payment.nrId, 'token': payment.payment_token, 'statusCode': payment.payment_status_code, 'completionDate': payment.payment_completion_date, 'payment': payment.as_dict(), 'sbcPayment': payment_response.to_dict() }) # Record the event nr_svc = self.nr_service # EventRecorder.record(nr_svc.user, Event.PATCH + ' [payment ID: {id}]'.format(id=payment.id), nr_model, data) response = make_response(data, 201) return response except PaymentServiceError as err: return handle_exception(err, err.message, 500) except SBCPaymentException as err: return handle_exception(err, err.message, err.status_code) except SBCPaymentError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, err, 500)
def get_waiting_time_dict(cls): try: if not (oldest_draft := Request.get_oldest_draft()): oldest_draft_date = datetime.now().astimezone() else: oldest_draft_date = oldest_draft.submittedDate # add one to waiting time to account for current day delta = datetime.now().astimezone( ) - oldest_draft_date + timedelta(days=1) response_data = { 'oldest_draft': oldest_draft_date.isoformat(), 'waiting_time': delta.days } except Exception as err: return handle_exception(err, repr(err), 500) return response_data @classmethod def get_statistics(cls): # For now not using this to improve performance # response_values = [cls.get_approved_names_counter(), # cls.get_waiting_time_priority_queue(unit=UnitTime.HR.value), # cls.get_waiting_time_regular_queue(unit=UnitTime.DAY.value)] oldest_draft = Request.get_oldest_draft() todays_date = get_utc_now().date() submitted_date = oldest_draft.submittedDate.date() # note that busday_count does not count the end date provided
def patch(self, nr_id, payment_id, payment_action): """ :param nr_id: :param payment_id: :param payment_action: :return: """ try: # Find the existing name request nr_model = RequestDAO.query.get(nr_id) # Creates a new NameRequestService, validates the app config, and sets request_data to the NameRequestService instance # Override the default self.initialize method def initialize(_self): # The request payload will be empty when making this call, # but we still want to process names, so we need to add # them to the request, otherwise they won't be processed! _self.request_data = { 'names': [n.as_dict() for n in nr_model.names.all()] } # Set the request data to the service _self.nr_service.request_data = self.request_data initialize(self) nr_svc = self.nr_service nr_svc.nr_num = nr_model.nrNum nr_svc.nr_id = nr_model.id valid_update_states = [ State.DRAFT, State.COND_RESERVE, State.RESERVED ] # This could be moved out, but it's fine here for now def validate_patch_request(nr): is_valid = True msg = '' if nr.stateCd in valid_update_states: is_valid = True return is_valid, msg is_valid_patch, validation_msg = validate_patch_request(nr_model) validation_msg = validation_msg if not len( validation_msg) > 0 else 'Invalid request for PATCH' if not is_valid_patch: raise PaymentServiceError(message=validation_msg) process_payment = has_active_payment(nr_model, payment_id) if nr_model.stateCd in valid_update_states and not process_payment: pass elif process_payment: # This handles updates if the NR state is 'patchable' nr_model = self.handle_payment_actions(payment_action, nr_model, payment_id) current_app.logger.debug(nr_model.json()) response_data = nr_model.json() # Add the list of valid Name Request actions for the given state to the response response_data['actions'] = nr_svc.current_state_actions return jsonify(response_data), 200 except PaymentServiceError as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, repr(err), 500)
def patch(self, nr_id, nr_action: str): """ Update a specific set of fields and/or a provided action. Fields excluded from the payload will not be updated. The following data format is expected when providing a data payload: { 'stateCd': 'CANCELLED' } # Fields to update We use this to: - Edit a subset of NR fields - Cancel an NR - Change the state of an NR :param nr_id: :param nr_action: One of [CHECKOUT, CHECKIN, EDIT, CANCEL, RESEND] :return: """ try: if not full_access_to_name_request(request): return { "message": "You do not have access to this NameRequest." }, 403 nr_action = str(nr_action).upper( ) # Convert to upper-case, just so we can support lower case action strings nr_action = NameRequestPatchActions[nr_action].value \ if NameRequestPatchActions.has_value(nr_action) \ else NameRequestPatchActions.EDIT.value # Find the existing name request nr_model = Request.query.get(nr_id) def initialize(_self): _self.validate_config(current_app) request_json = request.get_json() if nr_action: _self.nr_action = nr_action if nr_action is NameRequestPatchActions.CHECKOUT.value: # Make sure the NR isn't already checked out checked_out_by_different_user = nr_model.checkedOutBy is not None and nr_model.checkedOutBy != request_json.get( 'checkedOutBy', None) if checked_out_by_different_user: raise NameRequestIsInProgressError() # set the user id of the request to name_request_service_account service_account_user = User.find_by_username( 'name_request_service_account') nr_model.userId = service_account_user.id # The request payload will be empty when making this call, add them to the request _self.request_data = { # Doesn't have to be a UUID but this is easy and works for a pretty unique token 'checkedOutBy': str(uuid4()), 'checkedOutDt': datetime.now() } # Set the request data to the service _self.nr_service.request_data = self.request_data elif nr_action is NameRequestPatchActions.CHECKIN.value: # The request payload will be empty when making this call, add them to the request _self.request_data = { 'checkedOutBy': None, 'checkedOutDt': None } # Set the request data to the service _self.nr_service.request_data = self.request_data else: super().initialize() initialize(self) nr_svc = self.nr_service nr_svc.nr_num = nr_model.nrNum nr_svc.nr_id = nr_model.id # This could be moved out, but it's fine here for now def validate_patch_request(data): # Use the NR model state as the default, as the state change may not be included in the PATCH request request_state = data.get('stateCd', nr_model.stateCd) is_valid = False msg = '' # Handles updates if the NR state is 'patchable' if request_state in request_editable_states: is_valid = True elif request_state in contact_editable_states: is_valid = True else: msg = 'Invalid state change requested - the Name Request state cannot be changed to [' + data.get( 'stateCd', '') + ']' # Check the action, make sure it's valid if not NameRequestPatchActions.has_value(nr_action): is_valid = False msg = 'Invalid Name Request PATCH action, please use one of [' + ', '.join( [action.value for action in NameRequestPatchActions]) + ']' return is_valid, msg is_valid_patch, validation_msg = validate_patch_request( self.request_data) validation_msg = validation_msg if not len( validation_msg) > 0 else 'Invalid request for PATCH' if not is_valid_patch: raise InvalidInputError(message=validation_msg) def handle_patch_actions(action, model): return { NameRequestPatchActions.CHECKOUT.value: self.handle_patch_checkout, NameRequestPatchActions.CHECKIN.value: self.handle_patch_checkin, NameRequestPatchActions.EDIT.value: self.handle_patch_edit, NameRequestPatchActions.CANCEL.value: self.handle_patch_cancel, NameRequestPatchActions.RESEND.value: self.handle_patch_resend, NameRequestPatchActions.REQUEST_REFUND.value: self.handle_patch_request_refund }.get(action)(model) # This handles updates if the NR state is 'patchable' nr_model = handle_patch_actions(nr_action, nr_model) current_app.logger.debug(nr_model.json()) response_data = nr_model.json() # Don't return the whole response object if we're checking in or checking out if nr_action == NameRequestPatchActions.CHECKOUT.value: response_data = { 'id': nr_id, 'checkedOutBy': response_data.get('checkedOutBy'), 'checkedOutDt': response_data.get('checkedOutDt'), 'state': response_data.get('state', ''), 'stateCd': response_data.get('stateCd', ''), 'actions': nr_svc.current_state_actions } return jsonify(response_data), 200 if nr_action == NameRequestPatchActions.CHECKIN.value: response_data = { 'id': nr_id, 'state': response_data.get('state', ''), 'stateCd': response_data.get('stateCd', ''), 'actions': nr_svc.current_state_actions } return jsonify(response_data), 200 # Add the list of valid Name Request actions for the given state to the response if (nr_action == NameRequestPatchActions.REQUEST_REFUND.value): response_data['actions'] = [] else: response_data['actions'] = nr_svc.current_state_actions return jsonify(response_data), 200 except NameRequestIsInProgressError as err: # Might as well use the Mozilla WebDAV HTTP Locked status, it's pretty close return handle_exception(err, err.message, 423) except NameRequestException as err: return handle_exception(err, err.message, 500) except Exception as err: return handle_exception(err, repr(err), 500)