def complete_reapply_payment(self, nr_model: RequestDAO, payment_id: int): """ Invoked when re-applying for an existing Name Request reservation. Extend the Name Request's expiration date by 56 days. If the request action is set to REH or REST, extend the expiration by an additional year (plus the default 56 days). :param nr_model: :param payment_id: :return: """ nr_svc = self.nr_service # Update the state of the payment payment = get_active_payment(nr_model, payment_id) sbc_payment_response = get_payment(payment.payment_token) # TODO: Throw errors if this fails! if sbc_payment_response.statusCode in [ PaymentStatusCode.COMPLETED.value, PaymentStatusCode.APPROVED.value ]: payment.payment_status_code = sbc_payment_response.statusCode payment.payment_completion_date = sbc_payment_response.createdOn payment.save_to_db() if nr_model.submitCount < 3: if nr_model.request_action_cd in [ RequestAction.REH.value, RequestAction.REN.value ]: # If request action is REH or REST extend by 1 year (+ 56 default) days, starting tomorrow nr_model = nr_svc.extend_expiry_date(nr_model, datetime.utcnow(), days=421) nr_model = nr_svc.update_request_submit_count(nr_model) else: # Extend expiry date by (default) 56 days, starting tomorrow nr_model = nr_svc.extend_expiry_date(nr_model, datetime.utcnow(), days=56) nr_model = nr_svc.update_request_submit_count(nr_model) nr_model.save_to_db() else: # TODO: Make a custom exception for this? raise PaymentServiceError( message= 'Submit count maximum of 3 retries has been reached!') # This (optionally) handles the updates for NRO and Solr, if necessary update_solr = False nr_model = self.update_records_in_network_services( nr_model, update_solr) # Update the actions, as things change once the payment is successful self.nr_service.current_state_actions = get_nr_state_actions( nr_model.stateCd, nr_model) # Record the event # EventRecorder.record(nr_svc.user, Event.PATCH + ' [re-apply]', nr_model, nr_svc.request_data) return nr_model
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 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 _should_refund_sbc_payment(payment_token) -> bool: refund_sbc_payment = True payment_response = get_payment(payment_token) if payment_response.routingSlip: refund_sbc_payment = False elif len(payment_response.lineItems ) == 1 and payment_response.lineItems[0]['waivedBy']: refund_sbc_payment = False return refund_sbc_payment
def complete_reservation_payment(self, nr_model, payment_id): """ Invoked when completing an in-progress Name Request reservation. :param nr_model: :param payment_id: :return: """ nr_svc = self.nr_service # Update the state of the payment payment = get_active_payment(nr_model, payment_id) sbc_payment_response = get_payment(payment.payment_token) # TODO: Throw errors if this fails! if sbc_payment_response.status_code in [ PaymentStatusCode.COMPLETED.value ]: payment.payment_status_code = PaymentState.COMPLETED.value payment.payment_completion_date = sbc_payment_response.created_on payment.save_to_db() # Use apply_state_change to change state, as it enforces the State change pattern # apply_state_change takes the model, updates it to the specified state, and executes the callback handler # This handles updates if the NR state is DRAFT, COND_RESERVE or RESERVED # If the state is COND_RESERVE update state to CONDITIONAL # If the state is RESERVED update state to APPROVED # Then update the name request as required if nr_model.stateCd == State.DRAFT: # If the state is DRAFT, leave it as a DRAFT nr_model = nr_svc.apply_state_change(nr_model, State.DRAFT, self.handle_nr_approval) if nr_model.stateCd == State.COND_RESERVE: # If the state is COND_RESERVE update state to CONDITIONAL, and update the name request as required nr_model = nr_svc.apply_state_change(nr_model, State.CONDITIONAL, self.handle_nr_approval) elif nr_model.stateCd == State.RESERVED: # If the state is RESERVED update state to APPROVED, and update the name request as required nr_model = nr_svc.apply_state_change(nr_model, State.APPROVED, self.handle_nr_approval) # Save the name request nr_model.save_to_db() # Update the actions, as things change once the payment is successful self.nr_service.current_state_actions = get_nr_state_actions( nr_model.stateCd, nr_model) # Record the event # EventRecorder.record(nr_svc.user, Event.PATCH + ' [upgrade]', nr_model, nr_svc.request_data) return nr_model
def complete_reservation_payment(self, nr_model: RequestDAO, payment_id: int): """ Invoked when completing an in-progress Name Request reservation. :param nr_model: :param payment_id: :return: """ nr_svc = self.nr_service # Update the state of the payment payment = get_active_payment(nr_model, payment_id) sbc_payment_response = get_payment(payment.payment_token) # TODO: Throw errors if this fails! if sbc_payment_response.statusCode in [ PaymentStatusCode.COMPLETED.value, PaymentStatusCode.APPROVED.value ]: payment.payment_status_code = sbc_payment_response.statusCode payment.payment_completion_date = sbc_payment_response.createdOn payment.save_to_db() # This handles updates if the NR state is DRAFT, COND_RESERVE or RESERVED # If the state is COND_RESERVE update state to CONDITIONAL # If the state is RESERVED update state to APPROVED # Then update the name request as required if nr_model.stateCd == State.DRAFT: # If the state is DRAFT, leave it as a DRAFT nr_model = self.update_nr(nr_model, State.DRAFT, self.handle_nr_approve) if nr_model.stateCd == State.COND_RESERVE: # If the state is COND_RESERVE update state to CONDITIONAL, and update the name request as required nr_model = self.update_nr(nr_model, State.CONDITIONAL, self.handle_nr_approve) elif nr_model.stateCd == State.RESERVED: # If the state is RESERVED update state to APPROVED, and update the name request as required nr_model = self.update_nr(nr_model, State.APPROVED, self.handle_nr_approve) # Save the name request nr_model.save_to_db() # Record the event EventRecorder.record(nr_svc.user, Event.PATCH + ' [payment completed] RESERVE', nr_model, nr_model.json()) # Update the actions, as things change once the payment is successful self.nr_service.current_state_actions = get_nr_state_actions( nr_model.stateCd, nr_model) return nr_model
def handle_patch_request_refund(self, nr_model: Request): """ Can the NR and request a refund for ALL associated Name Request payments. :param nr_model: :return: """ nr_svc = self.nr_service # This handles updates if the NR state is 'patchable' nr_model = self.update_nr(nr_model, State.REFUND_REQUESTED, self.handle_nr_patch) # Handle the payments valid_states = [ PaymentState.APPROVED.value, PaymentState.COMPLETED.value, PaymentState.PARTIAL.value ] refund_value = 0 # Check for NR that has been renewed - do not refund any payments. # UI should not order refund for an NR renewed/reapplied it. if not any( payment.payment_action == Payment.PaymentActions.REAPPLY.value for payment in nr_model.payments.all()): # Try to refund all payments associated with the NR for payment in nr_model.payments.all(): if payment.payment_status_code in valid_states: # Some refunds may fail. Some payment methods are not refundable and return HTTP 400 at the refund. # The refund status is checked from the payment_response and a appropriate message is displayed by the UI. refund_payment(payment.payment_token, {}) payment_response = get_payment(payment.payment_token) payment.payment_status_code = PaymentState.REFUND_REQUESTED.value payment.save_to_db() refund_value += payment_response.receipts[0][ 'receiptAmount'] if len( payment_response.receipts) else 0 publish_email_notification(nr_model.nrNum, 'refund', '{:.2f}'.format(refund_value)) # This handles the updates for NRO and Solr, if necessary nr_model = self.update_records_in_network_services(nr_model, update_solr=True) # Record the event EventRecorder.record(nr_svc.user, Event.PATCH + ' [request-refund]', nr_model, nr_model.json()) return nr_model
def cancel_payment(self, nr_model: RequestDAO, payment_id: int): # Cancel payment with specified id. valid_states = [ PaymentState.CREATED.value ] for payment in nr_model.payments.all(): if payment.id == payment_id and payment.payment_status_code in valid_states: sbc_payment_response = get_payment(payment.payment_token) if sbc_payment_response.statusCode in [PaymentStatusCode.COMPLETED.value]: raise PaymentServiceError(message='Error cancelling payment. Payment is in a completed state!') cancel_payment(payment.payment_token) payment.payment_status_code = PaymentState.CANCELLED.value payment.save_to_db() return nr_model
def complete_upgrade_payment(self, nr_model: RequestDAO, payment_id: int): """ Invoked when upgrading an existing Name Request reservation to PRIORITY status. :param nr_model: :param payment_id: :return: """ nr_svc = self.nr_service if nr_model.stateCd not in [State.DRAFT, State.PENDING_PAYMENT]: raise PaymentServiceError( message= 'Error upgrading Name Request, request is in an invalid state!' ) # Update the state of the payment payment = get_active_payment(nr_model, payment_id) sbc_payment_response = get_payment(payment.payment_token) # TODO: Throw errors if this fails! if sbc_payment_response.statusCode in [ PaymentStatusCode.COMPLETED.value, PaymentStatusCode.APPROVED.value ]: payment.payment_status_code = sbc_payment_response.statusCode payment.payment_completion_date = sbc_payment_response.createdOn payment.save_to_db() nr_model.priorityCd = 'Y' nr_model.priorityDate = datetime.utcnow() # Save the name request nr_model.save_to_db() # This (optionally) handles the updates for NRO and Solr, if necessary update_solr = False nr_model = self.update_records_in_network_services( nr_model, update_solr) # Update the actions, as things change once the payment is successful self.nr_service.current_state_actions = get_nr_state_actions( nr_model.stateCd, nr_model) # Record the event EventRecorder.record(nr_svc.user, Event.PATCH + ' [payment completed] UPGRADE', nr_model, nr_model.json()) return nr_model
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.to_dict()) response = make_response(data, 200) return response except Exception as err: return jsonify(message=MSG_SERVER_ERROR + ' ' + str(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 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(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 cancel_payment(self, nr_model: RequestDAO, payment_id: int): # Cancel payment with specified id. valid_states = [PaymentState.CREATED.value] for payment in nr_model.payments.all(): if payment.id == payment_id and payment.payment_status_code in valid_states: sbc_payment_response = get_payment(payment.payment_token) if sbc_payment_response.statusCode in [ PaymentStatusCode.COMPLETED.value, PaymentStatusCode.APPROVED.value ]: raise PaymentServiceError( message= 'Error cancelling payment. Payment is in a completed state!' ) cancel_payment(payment.payment_token) payment.payment_status_code = PaymentState.CANCELLED.value payment.save_to_db() # record the event nr_svc = self.nr_service EventRecorder.record( nr_svc.user, Event.DELETE + f' [payment cancelled] {payment.payment_action}', nr_model, nr_model.json()) return nr_model
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 data = [] 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 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 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(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)