Ejemplo n.º 1
0
    def request_refund(self, nr_model: RequestDAO, payment_id: int):
        """
        Processes a SINGLE refund request.
        This is different from the 'refund' in the NameRequest resource PATCH namerequests/{nrId}/REQUEST_REFUND
        which cancels the NR and refunds any associated payments.
        :param nr_model:
        :param payment_id:
        :return:
        """
        # Handle the payments
        valid_states = [
            PaymentState.COMPLETED.value,
            PaymentState.PARTIAL.value
        ]
        if nr_model.stateCd not in [State.DRAFT]:
            raise PaymentServiceError(message='Invalid NR state for cancel and refund')
        # Cancel any payments associated with the NR
        for payment in nr_model.payments.all():
            if payment.payment_status_code in valid_states and payment.id == payment_id:
                # refund_payment(payment.payment_token, {'reason': 'Name Request user requested refund'})
                refund_payment(payment.payment_token, {})
                payment.payment_status_code = PaymentState.REFUND_REQUESTED.value
                payment.save_to_db()

        return nr_model
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
 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
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)