I have two departments that I need to run this for: Facilities and IT. This initiative is being executed concurrently with UAT. Already over 150k tickets have been migrated over; however, to keep it testable for our users, we need to make sure old ticket system updates that are currently happening are somewhat replicated in the new system.

First, I checked to see how many of the tickets I had in FC/IT were statused open. There were 208 open tickets for FC and 372 open tickets for IT. Then, out of the migrated tickets, I checked to see what the latest solarwinds ticket creation date was to get a grasp of when the CSV was pulled from Solarwinds. (Solarwinds does not allow for API integration and therefore requires us to manually pull a CSV file) The latest date was Nov 21, 2024 for FC and Dec 17, 2024 for IT (Non-sis) and Jan 6, 2025 for IT (SIS).

Facilities is simpler as they do not have various statuses, just open and closed, so the only additional information I would be adding to a ticket are:

IT have a little more complexity as the information that would be added to a ticket are:

Solarwinds statusJira mapped status
OpenWaiting for support
Waiting for responseWaiting for customer
ResolvedResolved
Appointment madeAppointment Made
DispatchDispatch
ClosedClosed
CancelledCanceled
PendingPending
Follow upWaiting for customer
RMAIn Progress
Waiting for DeliveryWaiting for Delivery
Converted to ProjectConverted to Project

First things first, we have to migrated over new tickets that were created in the span of the historical migration and update existing open tickets. To make things a bit easier, what I am going to do is just pull a csv for (1) opened tickets from Nov 21,2024 – Today for ALL tickets. And one more csv for (2) updated tickets from Nov 21, 2024 – Today.

(1) Opened tickets:

Import CSV to Fabric Lakehouse & request type mappings

I will then clean the opened_tickets with a dataflow gen2 and create some new columns by doing some data joins with the requesttype_mapping table. This will allow for me to deal with the complexity of having multiple projects, request types and sub request types.

Then, I created a notebook that will run every 5 minutes to create tickets that are not already in the jira projects. This GET endpoint: https://[company].atlassian.net/rest/api/3/search?jql=”Solarwinds Original Ticket Number[Short text]”~ “[ticket number]” will allow for creations of new tickets on a real-time basis.

Logic:

# JQL Query
    jql_query = f'"Solarwinds Original Ticket Number[Short text]"~ "{no}"'
    search_url = f"{jira_base_url}/rest/api/3/search"

    # Step 1: Search for existing issues
    get_response = requests.get(search_url, params={"jql": jql_query}, auth=auth, headers=headers)

    if get_response.json().get('total') < 1: 
        # Attempt to create the Jira issue (with potential retry)
        response = create_jira_issue(issue_payload)

(2) Updated Tickets

Import CSV to Fabric lakehouse. Then I will clean the updated_tickets with a dataflow gen2.

I then created a generalized updater with data mapping from old system statuses to new system statuses.

Logic:

 # JQL Query GET the ticket
    jql_query = f'"Solarwinds Original Ticket Number[Short text]"~ "{no}"'
    search_url = f"{jira_base_url}/rest/api/3/search"

    # Step 1: Search for existing issues
    get_response = requests.get(search_url, params={"jql": jql_query}, auth=auth, headers=headers)

    if get_response.json().get('total') >= 1:
        # Get the appropriate transition ID based on ticket_status
        ticket_status_lower = ticket_status.lower()

        if ticket_status_lower == 'resolved' or ticket_status_lower == 'cancelled':
            ticket_status_lower = 'closed'
        
        if rtkey.startswith("it/"):
            transition_id = status_to_transition_id.get(ticket_status_lower)
        elif rtkey.startswith("fc/"):
            transition_id = fc_status_id.get(ticket_status_lower)

        issue_key = get_response.json().get('issues', [])[0].get('key')

        issue_status = get_response.json().get('issues', [])[0].get('fields',[])['status']['name']

        search_comment_url = f"{jira_base_url}/rest/api/3/issue/{issue_key}/comment"
        get_comment_response = requests.get(search_comment_url, auth=auth, headers=headers)

        issue_comment = get_comment_response.json().get('comments', [])[0].get('body', []).get('content',[])[0].get('content',[])[0].get('text')
        

        if transition_id and (ticket_status_lower != issue_status.lower()):
            # Prepare the payload and make the transition request
            transition_payload = {"transition": {"id": transition_id}}
            transition_response = requests.post(
                f"{jira_base_url}/rest/api/3/issue/{issue_key}/transitions",
                auth=auth,
                headers=headers,
                data=json.dumps(transition_payload),
            )

            if transition_response.status_code == 400 or transition_response.status_code == 404:
                print(f"Bad request while transitioning ticket {issue_key} to '{ticket_status}'. Skipping transition.")
                continue
            elif transition_response.status_code == 204:
                print(f"Ticket {issue_key} transitioned to '{ticket_status}'.")

                # Additional final transition if status is "Closed"
                if ticket_status_lower in {"closed", "cancelled", "resolved"}:
                    final_transition_payload = {"transition": {"id": "941"}}
                    final_transition_response = requests.post(
                        f"{jira_base_url}/rest/api/3/issue/{issue_key}/transitions",
                        auth=auth,
                        headers=headers,
                        data=json.dumps(final_transition_payload),
                    )

                # Add notes as a comment
                formatted_notes = parse_notes(notes)
                comment_payload = {
                    "body": {
                        "type": "doc",
                        "version": 1,
                        "content": [{"type": "paragraph", "content": [{"text": str(formatted_notes), "type": "text"}]}]
                    }
                }
                comment_response = requests.post(
                    f"{jira_base_url}/rest/api/3/issue/{issue_key}/comment", 
                    auth=auth, headers=headers, data=json.dumps(comment_payload)
                )

                if comment_response.status_code == 400:
                    print(f"Bad request while adding comment to ticket {issue_key}. Skipping comment.")
                elif comment_response.status_code == 201:
                    print(f"Ticket {issue_key} inserted comment.")
            else:
                print(f"Unexpected status code: {transition_response.status_code} for ticket {issue_key}.")
        
        else:
            print(f"Unknown status '{ticket_status}'. No transition performed. OR same ticket status")
        

Leave a Reply