Advertisement
Guest User

Untitled

a guest
Mar 13th, 2024
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.90 KB | None | 0 0
  1. import os
  2. import json
  3. import pandas as pd
  4. import time
  5. import traceback
  6. from openpyxl import load_workbook
  7. from openpyxl.styles import numbers
  8. from datetime import datetime
  9.  
  10. BASE_DIR = os.path.dirname(__file__)
  11. CATEGORIES_FILE = os.path.join(BASE_DIR, "categories.json")
  12.  
  13. DEFAULT_CATEGORIES = {
  14. "Foods": [], "Beverages": [], "Cleaning": [], "Utilities": [], "Rent": [],
  15. "Interest Loans": [], "Advertising/Print/Decor": [], "Payroll": [],
  16. "Credit Fees": [], "Insurance": [], "Accounting": [], "Equipment/Furniture": [],
  17. "Repair/Maintenance": [], "License": [], "Misc": [], "Donations/Charity": [],
  18. "IRS": []
  19. }
  20.  
  21. def load_or_initialize_categories():
  22. if not os.path.exists(CATEGORIES_FILE):
  23. with open(CATEGORIES_FILE, 'w') as file:
  24. json.dump(DEFAULT_CATEGORIES, file, indent=4)
  25. return DEFAULT_CATEGORIES
  26. with open(CATEGORIES_FILE, 'r') as file:
  27. return json.load(file)
  28.  
  29. def save_categories(categories):
  30. with open(CATEGORIES_FILE, 'w') as file:
  31. json.dump(categories, file, indent=4)
  32.  
  33. def get_user_input(categories, recorder_name):
  34. date = input("Enter the date (MM/DD/YYYY): ")
  35. datetime_obj = datetime.strptime(date, "%m/%d/%Y")
  36. year = datetime_obj.strftime("%Y")
  37. month = datetime_obj.strftime("%B")
  38.  
  39. print("Categories:")
  40. for idx, cat in enumerate(categories.keys(), 1):
  41. print(f"{idx}. {cat}")
  42. category_choice = int(input("Select a category by number: "))
  43. category = list(categories.keys())[category_choice - 1]
  44.  
  45. print(f"Titles in {category}:")
  46. if categories[category]:
  47. for idx, title in enumerate(categories[category], 1):
  48. print(f"{idx}. {title}")
  49. title_choice = input("Select a title by number or enter a new one: ")
  50. if title_choice.isdigit():
  51. title = categories[category][int(title_choice) - 1]
  52. else:
  53. title = title_choice
  54. if title not in categories[category]:
  55. categories[category].append(title)
  56. else:
  57. title = input("Enter the first title for this category: ")
  58. categories[category].append(title)
  59.  
  60. amount = float(input("Enter the amount: "))
  61. addl_notes = input("Enter additional notes (if any): ")
  62.  
  63. return {"Date": date, "Recorder": recorder_name, "Category": category, "Title": title, "Amount": amount, "Addl. Notes": addl_notes}, year, month
  64.  
  65. def set_summary_formulas(ws):
  66. # Define headers for the summary columns
  67. ws['G1'] = "Total All"
  68. ws['H1'] = "COGS Amount"
  69. ws['I1'] = "COGS %"
  70. ws['J1'] = "OPEX Amount"
  71. ws['K1'] = "OPEX %"
  72. ws['L1'] = "Labor Amount"
  73. ws['M1'] = "Labor %"
  74.  
  75. # Total All formula
  76. ws['G2'] = f"=SUM(E2:E{ws.max_row})"
  77. ws['G2'].number_format = numbers.FORMAT_CURRENCY_USD_SIMPLE
  78.  
  79. # COGS related formulas
  80. ws['H2'] = f"=SUMIF(C2:C{ws.max_row}, \"Foods\", E2:E{ws.max_row}) + SUMIF(C2:C{ws.max_row}, \"Beverages\", E2:E{ws.max_row})"
  81. ws['I2'] = f"=H2/G2"
  82.  
  83. # OPEX related formulas
  84. opex_categories = ["Cleaning", "Utilities", "Rent", "Interest Loans", "Advertising",
  85. "Credit Fees", "Insurance", "Accounting", "Equipment", "Repair", "License", "Misc", "Donations"]
  86. opex_formula = " + ".join([f'SUMIF(C2:C{ws.max_row}, "{cat}", E2:E{ws.max_row})' for cat in opex_categories])
  87. ws['J2'] = f"=({opex_formula})"
  88. ws['K2'] = f"=J2/G2"
  89.  
  90. # Labor related formulas
  91. ws['L2'] = f"=SUMIF(C2:C{ws.max_row}, \"Payroll\", E2:E{ws.max_row}) + SUMIF(C2:C{ws.max_row}, \"IRS\", E2:E{ws.max_row})"
  92. ws['M2'] = f"=L2/G2"
  93.  
  94. # Apply number formatting for financial and percentage columns
  95. for col in ['H2', 'J2', 'L2']:
  96. ws[col].number_format = numbers.FORMAT_CURRENCY_USD_SIMPLE
  97. for col in ['I2', 'K2', 'M2']:
  98. ws[col].number_format = numbers.FORMAT_PERCENTAGE_00
  99.  
  100.  
  101. def ensure_directories(year, month, category, title):
  102. paths = {
  103. "month_dir": os.path.join(BASE_DIR, year, month),
  104. "category_dir_month": os.path.join(BASE_DIR, year, month, "Categories", category),
  105. "title_dir_month": os.path.join(BASE_DIR, year, month, "Categories", category, "Titles", title),
  106. "year_dir": os.path.join(BASE_DIR, year),
  107. "category_dir_year": os.path.join(BASE_DIR, year, "Categories", category),
  108. "title_dir_year": os.path.join(BASE_DIR, year, "Categories", category, "Titles", title)
  109. }
  110. for path in paths.values():
  111. os.makedirs(path, exist_ok=True)
  112. return paths
  113.  
  114. def update_excel(file_path, data, is_overall_summary):
  115. file_path = Path(file_path)
  116. os.makedirs(file_path.parent, exist_ok=True)
  117.  
  118. mode = 'a' if file_path.exists() else 'w'
  119. sheet_name = 'Sheet1'
  120.  
  121. with pd.ExcelWriter(file_path, engine='openpyxl', mode=mode, if_sheet_exists='overlay') as writer:
  122. if mode == 'a':
  123. book = load_workbook(file_path)
  124. if sheet_name in book.sheetnames:
  125. start_row = book[sheet_name].max_row
  126. else:
  127. start_row = 0
  128. else:
  129. start_row = 0
  130.  
  131. df = pd.DataFrame([data])
  132. df.to_excel(writer, sheet_name=sheet_name, index=False, header=(start_row == 0), startrow=start_row)
  133.  
  134. if is_overall_summary:
  135. wb = load_workbook(file_path)
  136. ws = wb[sheet_name]
  137. set_summary_formulas(ws)
  138. wb.save(file_path)
  139.  
  140. def apply_column_formatting(ws):
  141. # Set column widths
  142. for col_letter in 'ABCDEFGHIJKLMN':
  143. ws.column_dimensions[col_letter].width = 22
  144.  
  145. # Format rows starting from the second
  146. for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
  147. row[0].number_format = 'MM/DD/YYYY' # Date format
  148. row[4].number_format = numbers.FORMAT_CURRENCY_USD_SIMPLE # Currency format for the Amount column
  149. # Extend this section if more specific formatting is needed for other columns
  150.  
  151.  
  152.  
  153.  
  154. def main():
  155. categories = load_or_initialize_categories()
  156. recorder_name = input("Enter the recorder's name: ")
  157. continue_recording = 'yes'
  158.  
  159. while continue_recording.lower() == 'yes':
  160. try:
  161. data, year, month = get_user_input(categories, recorder_name)
  162. save_categories(categories)
  163.  
  164. paths = ensure_directories(year, month, data["Category"], data["Title"])
  165.  
  166. # File paths
  167. monthly_summary_file = os.path.join(paths["month_dir"], f'{month}_Monthly_Summary.xlsx')
  168. category_summary_file_month = os.path.join(paths["category_dir_month"], f'{data["Category"]}_Category_Summary.xlsx')
  169. title_summary_file_month = os.path.join(paths["title_dir_month"], f'{data["Title"]}_Title_Summary.xlsx')
  170.  
  171. yearly_summary_file = os.path.join(paths["year_dir"], f'{year}_Yearly_Summary.xlsx')
  172. category_summary_file_year = os.path.join(paths["category_dir_year"], f'{data["Category"]}_Year_Category_Summary.xlsx')
  173. title_summary_file_year = os.path.join(paths["title_dir_year"], f'{data["Title"]}_Year_Title_Summary.xlsx')
  174.  
  175. # Update Excel files with a delay to avoid conflicts
  176. files_to_update = [
  177. (monthly_summary_file, True),
  178. (category_summary_file_month, False),
  179. (title_summary_file_month, False),
  180. (yearly_summary_file, True),
  181. (category_summary_file_year, False),
  182. (title_summary_file_year, False)
  183. ]
  184.  
  185. for file_path, is_overall in files_to_update:
  186. update_excel(file_path, data, is_overall_summary=is_overall)
  187.  
  188. except Exception as e:
  189. print("An error occurred during the update process:")
  190. print(e)
  191. traceback.print_exc() # To print the stack trace and understand where the error occurred
  192.  
  193. continue_recording = input("Would you like to record another expense? (yes/no): ")
  194.  
  195. if __name__ == "__main__":
  196. main()
  197.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement