SelwynChan / HelloWorld

My first Git Repository
0 stars 0 forks source link

Db #11

Open SelwynChan opened 1 year ago

SelwynChan commented 1 year ago

First, install the required packages:

pip install pyodbc PyYAML

Now, create a config.yaml file with the server details:

oma_history_server: <history_server_address>
oma_archive_server: <archive_server_address>

Here's the full Python code that meets your requirements:

import os
import pyodbc
import yaml
import csv
from tkinter import Tk, Label, Entry, Button, messagebox

def read_config(file_path):
    with open(file_path, "r") as file:
        config = yaml.safe_load(file)
    return config

def get_database_connection(driver, server, user, password, database):
    conn_str = f"DRIVER={{{driver}}};SERVER={server};UID={user};PWD={password};DATABASE={database}"
    conn = pyodbc.connect(conn_str)
    return conn

def close_database_connection(conn):
    if conn:
        conn.close()

def find_data_in_database(conn, received_order_id):
    with conn.cursor() as cursor:
        sql = "SELECT * FROM OmaOrderData WHERE receivedOrderID = ?"
        cursor.execute(sql, (received_order_id,))
        result = cursor.fetchone()
    return result

def get_oma_archive_databases(conn):
    with conn.cursor() as cursor:
        cursor.execute("SELECT name FROM sys.databases WHERE name LIKE 'p_oma_archive_%' ORDER BY name DESC")
        databases = [row[0] for row in cursor]
    return databases

def retrieve_data_from_databases(driver, history_server, history_user, history_password, archive_server, archive_user, archive_password, received_order_id):
    conn = get_database_connection(driver, history_server, history_user, history_password, "p_oma_history")
    data = find_data_in_database(conn, received_order_id)
    close_database_connection(conn)

    if not data:
        conn = get_database_connection(driver, archive_server, archive_user, archive_password, None)
        archive_databases = get_oma_archive_databases(conn)
        close_database_connection(conn)

        for db in archive_databases:
            conn = get_database_connection(driver, archive_server, archive_user, archive_password, db)
            data = find_data_in_database(conn, received_order_id)
            close_database_connection(conn)

            if data:
                break

    return data

def write_data_to_csv(output_directory, received_order_id, data):
    if not os.path.exists(output_directory):
        os.makedirs(output_directory)

    csv_file_path = os.path.join(output_directory, f"{received_order_id}.csv")

    with open(csv_file_path, "w", newline="") as file:
        writer = csv.writer(file)
        writer.writerow(data._fields)
        writer.writerow(data)

def retrieve_and_export_order_data(config, output_directory, login_details):
    driver, history_server, history_user, history_password = login_details["history"]
    archive_server, archive_user, archive_password = login_details["archive"]

    for logical_order_id, received_order_id in config["loid_roid_mapping"].items():
        try:
            data = retrieve_data_from_databases(
                driver, history_server, history_user, history_password,
                archive_server, archive_user, archive_password, received_order_id
            )
            write_data_to_csv(output_directory, received_order_id, data)
        except Exception as e:
            print(f"Error processing receivedOrderID {received_order_id}: {e}")

def get_login_details(driver):
    def on_submit():
        history_user = history_user_entry.get()
        history_password = history_password_entry.get()
        archive_user = archive_user_entry.get()
        archive_password = archive_password_entry.get()

        login_details = {
            "history": (driver, config["oma_history_server"], history_user, history_password),
            "archive": (driver, config["oma_archive_server"], archive_user, archive_password)
        }

        window.destroy()
        retrieve_and_export_order_data(config, output_directory, login_details)

    window = Tk()
    window.title("Enter Login Details")

    Label(window, text="History User:").grid(row=0, column=0)
    history_user_entry = Entry(window)
    history_user_entry.grid(row=0, column=1)

    Label(window, text="History Password:").grid(row=1, column=0)
    history_password_entry = Entry(window, show="*")
    history_password_entry.grid(row=1, column=1)

    Label(window, text="Archive User:").grid(row=2, column=0)
    archive_user_entry = Entry(window)
    archive_user_entry.grid(row=2, column=1)

    Label(window, text="Archive Password:").grid(row=3, column=0)
    archive_password_entry = Entry(window, show="*")
    archive_password_entry.grid(row=3, column=1)

    submit_button = Button(window, text="Submit", command=on_submit)
    submit_button.grid(row=4, columnspan=2)

    window.mainloop()

# Example usage:
config_file = "config.yaml"
output_directory = "output"
driver = "Adaptive Server Enterprise"

config = read_config(config_file)
get_login_details(driver)

This code uses tkinter to create a simple UI for the user to enter login details. The retrieve_and_export_order_data() function retrieves data from the oma_history and oma_archive databases and writes it to CSV files in the output directory. The retrieve_data_from_databases() function searches for the receivedOrderID in the oma_history database first and then searches the oma_archive databases in reverse chronological order.

Make sure to replace <history_server_address> and <archive_server_address> in the config.yaml file with the correct server addresses. The user only needs to provide login details once for each run. The code ensures that database connections are properly closed, even in case of exceptions, and is designed to be modular, extendable, and well-organized.

SelwynChan commented 1 year ago

You can modify the retrieve_and_export_order_data() function to accept the loid_roid_mapping and output_directory as arguments. Then, you can call this function from your other function to trigger the retrieval job.

Here's the slightly modified version of the retrieve_and_export_order_data() function:

def retrieve_and_export_order_data(loid_roid_mapping, output_directory, login_details):
    driver, history_server, history_user, history_password = login_details["history"]
    archive_server, archive_user, archive_password = login_details["archive"]

    for logical_order_id, received_order_id in loid_roid_mapping.items():
        try:
            data = retrieve_data_from_databases(
                driver, history_server, history_user, history_password,
                archive_server, archive_user, archive_password, received_order_id
            )
            write_data_to_csv(output_directory, received_order_id, data)
        except Exception as e:
            print(f"Error processing receivedOrderID {received_order_id}: {e}")

Now, from your other function, you can call retrieve_and_export_order_data() with the loid_roid_mapping and output_directory as arguments. For example:

def your_function():
    # Your code...
    loid_roid_mapping = {
        "logicalOrderID1": "receivedOrderID1",
        "logicalOrderID2": "receivedOrderID2"
    }
    output_directory = "output"

    get_login_details(driver)
    retrieve_and_export_order_data(loid_roid_mapping, output_directory, login_details)

Make sure to have the login_details variable accessible in the scope of your function or pass it as an argument as well. This way, you can trigger the retrieval job with the specified loid_roid_mapping and output_directory.