Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
jottavia authored Apr 16, 2024
1 parent 2f07781 commit 76ceb39
Showing 1 changed file with 292 additions and 0 deletions.
292 changes: 292 additions & 0 deletions nben902-editor-1.4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
import tkinter as tk
from tkinter import filedialog, messagebox
import pandas as pd
import re
import subprocess
import os

class EditableTable(tk.Frame):
def __init__(self, parent, columns):
super().__init__(parent)
self.columns = columns
self.grid(sticky='nsew')
self.create_widgets()
self.effective_date = ""

def create_widgets(self):
self.entries = []
self.labels = []
self.delete_buttons = []
self.duplicate_buttons = []
for col, (column_name, width) in enumerate(self.columns):
label = tk.Label(self, text=column_name, relief='ridge')
label.grid(row=0, column=col + 1) # Updated column to add space for Duplicate button
self.labels.append(label)

def load_data(self, df):
self.clear_table()

for row, record in df.iterrows():
self.add_row(record)

def add_row(self, record=None):
duplicate_button = tk.Button(self, text="Duplicate", command=lambda row=len(self.entries): self.duplicate_row(row))
duplicate_button.grid(row=len(self.entries) + 1, column=0) # Moved duplicate button to the left of the row
self.duplicate_buttons.append(duplicate_button)

entries_row = []
for col, (column_name, width) in enumerate(self.columns):
if record is None:
if column_name == "Employee ID":
value = "N"
elif column_name == "Effective Date":
value = self.effective_date
else:
value = ""
elif pd.isna(record[column_name]) and column_name == "Deduction End Date":
value = ""
else:
value = record[column_name]
if column_name == "Name":
value = value.upper()
entry = tk.Entry(self, width=width)
entry.insert(0, value)
entry.grid(row=len(self.entries) + 1, column=col + 1) # Updated column to add space for Duplicate button

if column_name == "Effective Date":
entry.bind("<FocusOut>", lambda event, row=len(self.entries), col=col: self.update_effective_date(row, col))

entries_row.append(entry)
self.entries.append(entries_row)

delete_button = tk.Button(self, text="Delete", command=lambda row=len(self.entries) - 1: self.delete_row(row))
delete_button.grid(row=len(self.entries), column=len(self.columns) + 1)
self.delete_buttons.append(delete_button)

def update_effective_date(self, row, col):
effective_date = self.entries[row][col].get()
if re.match(r'^\d{2}-\d{2}-\d{4}$', effective_date):
self.effective_date = effective_date
for r in range(len(self.entries)):
self.entries[r][col].delete(0, tk.END)
self.entries[r][col].insert(0, effective_date)

def delete_row(self, row):
for entry in self.entries[row]:
entry.destroy()
self.entries.pop(row)

self.delete_buttons[row].destroy()
self.delete_buttons.pop(row)

self.duplicate_buttons[row].destroy()
self.duplicate_buttons.pop(row)

for i in range(row, len(self.entries)):
for col, entry in enumerate(self.entries[i]):
entry.grid(row=i + 1, column=col + 1) # Updated column to add space for Duplicate button
self.delete_buttons[i].grid(row=i + 1, column=len(self.columns) + 1)
self.delete_buttons[i].config(command=lambda row=i: self.delete_row(row))

self.duplicate_buttons[i].grid(row=i + 1, column=0) # Moved duplicate button to the left of the row
self.duplicate_buttons[i].config(command=lambda row=i: self.duplicate_row(row))

def duplicate_row(self, row):
record_values = [entry.get() for entry in self.entries[row]]
record = pd.Series(record_values, index=[col[0] for col in self.columns])
self.add_row(record)
self.duplicate_buttons[-1].config(command=lambda row=len(self.entries) - 1: self.duplicate_row(row))

def clear_table(self):
for row in self.entries:
for entry in row:
entry.destroy()
self.entries = []

for button in self.delete_buttons:
button.destroy()
self.delete_buttons = []

def get_data(self):
data = []
for row_idx, row in enumerate(self.entries):
record = []
for col, (column_name, width) in enumerate(self.columns):
value = row[col].get()

if not self.validate_value(column_name, value):
messagebox.showerror("Input Validation Error", f"Invalid value for {column_name} at row {row_idx + 1}.")
return None

if column_name == "Name":
value = value.upper()
record.append(value)
data.append(record)
return data

@staticmethod
def validate_value(column_name, value):
if column_name == "Agency Code":
return bool(value)
elif column_name == "Name":
return bool(value)
elif column_name == "Employee ID":
return re.match(r'^N\d{8}$', value)
elif column_name == "Deduction Code":
return bool(value)
elif column_name == "Effective Date":
return re.match(r'^\d{2}-\d{2}-\d{4}$', value)
elif column_name == "Deduction End Date":
return value == "" or re.match(r'^\d{2}-\d{2}-\d{4}$', value)
elif column_name == "Deduction Amount":
return value.replace(".", "", 1).isdigit() and float(value) > 0
else:
return False

def parse_fixed_width_file(file_path):
colspecs = [(0, 10), (10, 60), (60, 69), (69, 75), (75, 85), (85, 95), (95, 103)]
column_names = ["Agency Code", "Name", "Employee ID", "Deduction Code", "Effective Date", "Deduction End Date", "Deduction Amount"]
df = pd.read_fwf(file_path, colspecs=colspecs, header=None, names=column_names, converters={'Agency Code': str})
return df

def save_data(df, file_path):
col_widths = [10, 50, 9, 6, 10, 10, 8]
with open(file_path, "w") as file:
for _, row in df.iterrows():
row_str = ""
for idx, value in enumerate(row):
if idx == 4 or idx == 5: # Effective Date and Deduction End Date columns
if value == "":
value = " " * col_widths[idx]
if idx == 6: # Deduction Amount field
formatted_value = str(value).rjust(col_widths[idx], '0')
else:
formatted_value = str(value).ljust(col_widths[idx], ' ')
row_str += formatted_value[:col_widths[idx]]
file.write(row_str + "\n")

def main():
root = tk.Tk()
root.title("Fixed-Width File Editor")
root.geometry("1000x600")

file_path, df = None, pd.DataFrame()

columns = [
("Agency Code", 10),
("Name", 50),
("Employee ID", 10),
("Deduction Code", 6),
("Effective Date", 10),
("Deduction End Date", 10),
("Deduction Amount", 8)
]

def open_file():
nonlocal file_path, df
file_path = filedialog.askopenfilename()
if not file_path:
return
df = parse_fixed_width_file(file_path)
editable_table.load_data(df)

def save_file():
nonlocal file_path, df
save_file_path = filedialog.asksaveasfilename(initialfile=os.path.basename(file_path))
if not save_file_path:
return
data = editable_table.get_data()
if data is None:
return
df = pd.DataFrame(data, columns=[col[0] for col in columns])
save_data(df, save_file_path)

def add_new_row():
nonlocal editable_table
editable_table.add_row()

def convert_902():
current_directory = os.path.dirname(os.path.abspath(__file__))
try:
subprocess.run(["convert-902.exe"], check=True, cwd=current_directory)
except Exception as e:
messagebox.showerror("Error", f"Error running convert-902: {str(e)}")

def transmit_902():
current_directory = os.path.dirname(os.path.abspath(__file__))
try:
subprocess.run(["902-sftp.exe"], check=True, cwd=current_directory)
except Exception as e:
messagebox.showerror("Error", f"Error running 902-sftp: {str(e)}")

def close_app():
data = editable_table.get_data()
if data is None:
return
new_df = pd.DataFrame(data, columns=[col[0] for col in columns])

if not new_df.equals(df):
response = messagebox.askyesnocancel("Save Changes", "Do you want to save changes before closing?")
if response is None:
return
elif response:
save_file()

root.destroy()

# Button Frame
button_frame = tk.Frame(root)
button_frame.grid(row=0, column=0, sticky="nw")

open_button = tk.Button(button_frame, text="Open", command=open_file)
open_button.pack(side="left", padx=(10, 5), pady=5)

save_button = tk.Button(button_frame, text="Save", command=save_file)
save_button.pack(side="left", padx=(0, 5), pady=5)

add_row_button = tk.Button(button_frame, text="Add Row", command=add_new_row)
add_row_button.pack(side="left", padx=(0, 5), pady=5)

convert_902_button = tk.Button(button_frame, text="Convert-902", command=convert_902)
convert_902_button.pack(side="left", padx=(0, 5), pady=5)

transmit_902_button = tk.Button(button_frame, text="Transmit 902", command=transmit_902)
transmit_902_button.pack(side="left", padx=(0, 5), pady=5)

exit_button = tk.Button(button_frame, text="Exit", command=root.quit)
exit_button.pack(side="left", padx=(0, 10), pady=5)

# Table Frame
table_frame = tk.Frame(root)
table_frame.grid(row=1, column=0, sticky="nsew")

root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)

canvas = tk.Canvas(table_frame)
canvas.grid(row=0, column=0, sticky="nsew")

table_frame.grid_rowconfigure(0, weight=1)
table_frame.grid_columnconfigure(0, weight=1)

editable_table = EditableTable(canvas, columns=columns)
canvas.create_window((0, 0), window=editable_table, anchor="nw")

def update_scrollregion(event):
canvas.configure(scrollregion=canvas.bbox("all"))

editable_table.bind("<Configure>", update_scrollregion)

scrollbar_y = tk.Scrollbar(table_frame, orient="vertical", command=canvas.yview)
scrollbar_y.grid(row=0, column=1, sticky="ns")
canvas.configure(yscrollcommand=scrollbar_y.set)

scrollbar_x = tk.Scrollbar(root, orient="horizontal", command=canvas.xview)
scrollbar_x.grid(row=2, column=0, sticky="ew")
canvas.configure(xscrollcommand=scrollbar_x.set)

root.protocol("WM_DELETE_WINDOW", close_app)
root.mainloop()

if __name__ == "__main__":
main()

0 comments on commit 76ceb39

Please sign in to comment.