diff --git a/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/services.py b/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/services.py index cb59484..7d035ad 100644 --- a/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/services.py +++ b/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/services.py @@ -33,7 +33,6 @@ def setup_folders(): ensure_folder_exists(UPDATE_ORDNER_NAME_USER) ensure_folder_exists(SETTINGS_ORDNER) pass - def ensure_folder_exists(folder_name): base_dir = get_base_dir_path() @@ -96,7 +95,6 @@ def get_help_file_path(app): def get_base_dir(): return get_base_dir_path() - def get_settings(): settings_file = get_settings_file_path() if os.path.exists(settings_file): @@ -109,6 +107,11 @@ def set_settings(settings): with open(settings_file, "w") as file: json.dump(settings, file, indent=4) +def get_settings_file_path(): + settings_folder = ensure_folder_exists(SETTINGS_ORDNER) + settings_file = os.path.join(settings_folder, "settings.json") + return settings_file + def set_user_code(user_code): settings = get_settings() settings["user_code"] = user_code @@ -127,6 +130,63 @@ def audio_zu_text_konvertieren(audio_dateipfad): result = model.transcribe(audio_dateipfad) return result["text"] +def load_settings(): + settings_file = get_settings_file_path() + if os.path.exists(settings_file): + with open(settings_file, "r") as file: + return json.load(file) + else: + return {} + + +def measure_execution_time(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + start_time = time.time() + result = func(*args, **kwargs) + end_time = time.time() + execution_time = end_time - start_time + #print(f"Die Funktion '{func.__name__}' hat {execution_time:.2f} Sekunden gedauert.") + return result + return wrapper + +def ermittel_den_aktuellen_monat_als_deutsches_wort(monat_offset=0): + """ + Ermittelt den Monat relativ zum aktuellen Monat als Zahl und gibt den entsprechenden deutschen Monatsnamen zurück. + + Args: + monat_offset (int, optional): Die Anzahl der Monate, die zum aktuellen Monat addiert werden sollen. Standard ist 0. + + Returns: + str: Der ermittelte Monat auf Deutsch (z.B. "Januar", "Februar", ...). + """ + # Erstelle ein Dictionary, das die Monatszahlen auf die deutschen Monatsnamen abbildet + monatsnamen = { + 1: "Januar", + 2: "Februar", + 3: "März", + 4: "April", + 5: "Mai", + 6: "Juni", + 7: "Juli", + 8: "August", + 9: "September", + 10: "Oktober", + 11: "November", + 12: "Dezember" + } + + # Ermittle den aktuellen Monat als Zahl + aktueller_monat_als_zahl = datetime.now().month + + # Addiere den Offset zum aktuellen Monat + ziel_monat = (aktueller_monat_als_zahl + monat_offset) % 12 + if ziel_monat == 0: + ziel_monat = 12 + + # Gib den entsprechenden deutschen Monatsnamen zurück + return monatsnamen[ziel_monat] + """ #TODO #96 Veralgemeinern def update_daten_in_basis_ordner_uebertragen(app): @@ -202,4 +262,732 @@ def vorlagen_in_vorlagen_ordner_uebertragen(app): # Umbenennen der "update_"-Datei im Anwendungsordner, indem das "update_" Präfix entfernt wird neuer_app_pfad_ohne_update = os.path.join(vorlagen_ordner_app, neuer_name_ohne_update) os.rename(vorlage_app_pfad, neuer_app_pfad_ohne_update) -""" \ No newline at end of file +""" + + + + +#LaunchPad + +def ermittel_den_aktuellen_monat_als_deutsches_wort(monat_offset=0): + """ + Ermittelt den Monat relativ zum aktuellen Monat als Zahl und gibt den entsprechenden deutschen Monatsnamen zurück. + + Args: + monat_offset (int, optional): Die Anzahl der Monate, die zum aktuellen Monat addiert werden sollen. Standard ist 0. + + Returns: + str: Der ermittelte Monat auf Deutsch (z.B. "Januar", "Februar", ...). + """ + # Erstelle ein Dictionary, das die Monatszahlen auf die deutschen Monatsnamen abbildet + monatsnamen = { + 1: "Januar", + 2: "Februar", + 3: "März", + 4: "April", + 5: "Mai", + 6: "Juni", + 7: "Juli", + 8: "August", + 9: "September", + 10: "Oktober", + 11: "November", + 12: "Dezember" + } + + # Ermittle den aktuellen Monat als Zahl + aktueller_monat_als_zahl = datetime.now().month + + # Addiere den Offset zum aktuellen Monat + ziel_monat = (aktueller_monat_als_zahl + monat_offset) % 12 + if ziel_monat == 0: + ziel_monat = 12 + + # Gib den entsprechenden deutschen Monatsnamen zurück + return monatsnamen[ziel_monat] + +#LAW + +import json +import requests +from requests.auth import HTTPBasicAuth +import logging +import os +import uuid +import shutil +from nadoo_law.CONSTANTS import TEMP_FOLDER, BASE_DIR,MANDATEN_ORDNER_NAME,KUNDENDATEN_ORDNER_APP, UPDATE_ORDNER_NAME_APP, UPDATE_ORDNER_NAME_USER,VORLAGEN_ORDNER_APP, ARCHIV_ORDNER +from datetime import datetime +import subprocess +import platform + +from nadoo_law.utils import ( + ensure_beweismittel_OWi_data_file_exists, + ensure_beweismittel_Scheidung_data_file_exists, + ensure_data_file_exists, + ensure_lawyer_data_file_exists, + get_base_dir_path, + get_ausfuehrungen_file_path, + get_beweismittel_OWi_data_file_path, + get_beweismittel_Scheidung_data_file_path, + get_lawyer_data_file_path, + ensure_folder_exists, + get_login_information, + set_login_information, +) + + + +def set_beweismittel_data_Scheidung(beweismittel_data): + ensure_beweismittel_Scheidung_data_file_exists() + file_path = get_beweismittel_Scheidung_data_file_path() + with open(file_path, "w") as f: + json.dump(beweismittel_data, f, indent=4) + + +def get_beweismittel_data_scheidung(): + ensure_beweismittel_Scheidung_data_file_exists() + file_path = get_beweismittel_Scheidung_data_file_path() + with open(file_path, "r") as f: + return json.load(f) + +def set_beweismittel_data_OWi(beweismittel_data): + ensure_beweismittel_OWi_data_file_exists() + file_path = get_beweismittel_OWi_data_file_path() + with open(file_path, "w") as f: + json.dump(beweismittel_data, f, indent=4) + + +def get_beweismittel_data_OWi(): + ensure_beweismittel_OWi_data_file_exists() + file_path = get_beweismittel_OWi_data_file_path() + with open(file_path, "r") as f: + return json.load(f) + + + +def set_lawyer_data(lawyer_data): + ensure_lawyer_data_file_exists() + file_path = get_lawyer_data_file_path() + with open(file_path, "w") as f: + json.dump(lawyer_data, f, indent=4) + + +def get_lawyer_data(): + ensure_lawyer_data_file_exists() + file_path = get_lawyer_data_file_path() + with open(file_path, "r") as f: + return json.load(f) + + +def setup_folders(): + ensure_folder_exists(get_template_folder()) + ensure_folder_exists(get_temp_folder()) + ensure_folder_exists(get_mandanten_folder()) + versionsordner_erstellen() + + +def vorlagen_in_vorlagen_ordner_uebertragen(app): + vorlagen_ordner_app = os.path.join(app.paths.app, "resources", KUNDENDATEN_ORDNER_APP, VORLAGEN_ORDNER_APP) + vorlagen_ordner_user = get_template_folder() # Annahme, dass diese Funktion das Benutzerverzeichnis für Vorlagen zurückgibt + archiv_ordner = os.path.join(vorlagen_ordner_user, ARCHIV_ORDNER) + placeholder_file_name = "placeholder.txt" + + # Stelle sicher, dass der Archivordner existiert + if not os.path.exists(archiv_ordner): + os.makedirs(archiv_ordner) + + # Überprüfe, ob der Vorlagenordner existiert + if not os.path.isdir(vorlagen_ordner_app): + return # Beende die Funktion, wenn der Ordner nicht existiert + + for file in os.listdir(vorlagen_ordner_app): + if file == placeholder_file_name: + continue # Ignoriere die Platzhalterdatei + + vorlage_app_pfad = os.path.join(vorlagen_ordner_app, file) + neuer_name_ohne_update = file.replace("update_", "") + vorlage_user_pfad = os.path.join(vorlagen_ordner_user, neuer_name_ohne_update) + + # Wenn es sich um eine Update-Datei handelt ODER keine Datei im Benutzerverzeichnis existiert, führe den Kopiervorgang durch + if file.startswith("update_") or not os.path.exists(vorlage_user_pfad): + if os.path.exists(vorlage_user_pfad): + # Archiviere die existierende Datei, bevor sie durch die Update-Datei ersetzt wird + basisname, erweiterung = os.path.splitext(neuer_name_ohne_update) + datumsanhang = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + archivierte_datei_name = f"{basisname}_{datumsanhang}{erweiterung}" + shutil.move(vorlage_user_pfad, os.path.join(archiv_ordner, archivierte_datei_name)) + + # Kopiere die Vorlage oder aktualisierte Vorlage in das Benutzerverzeichnis + shutil.copy(vorlage_app_pfad, vorlage_user_pfad) + + if file.startswith("update_"): + # Umbenennen der "update_"-Datei im Anwendungsordner, indem das "update_" Präfix entfernt wird + neuer_app_pfad_ohne_update = os.path.join(vorlagen_ordner_app, neuer_name_ohne_update) + os.rename(vorlage_app_pfad, neuer_app_pfad_ohne_update) + +def anwalt_liste_in_basis_ordner_uebertragen(app): + kundendaten_ordner_app = os.path.join(app.paths.app, "resources", KUNDENDATEN_ORDNER_APP) + basis_ordner_user = get_base_dir() # Angenommen, diese Funktion gibt den Basisordner des Benutzers zurück + archiv_ordner = os.path.join(basis_ordner_user,ARCHIV_ORDNER, "archivierte_anwalt_daten") + name_der_anwalt_daten_json_datei = "lawyer_details.json" + update_datei_name = "update_lawyer_details.json" + + ziel_datei_pfad = os.path.join(basis_ordner_user, name_der_anwalt_daten_json_datei) + update_datei_pfad = os.path.join(kundendaten_ordner_app, update_datei_name) + + # Stelle sicher, dass der Archivordner existiert + if not os.path.exists(archiv_ordner): + os.makedirs(archiv_ordner) + + # Überprüfe, ob die Datei lawyer_details.json bereits im Zielordner existiert + if os.path.isfile(ziel_datei_pfad): + # Wenn ja, und update_lawyer_details.json ist vorhanden, archiviere die alte Datei + if os.path.isfile(update_datei_pfad): + # Generiere einen eindeutigen Namen für die archivierte Datei + datumsanhang = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + archivierte_datei_name = f"lawyer_details_{datumsanhang}.json" + archivierte_datei_pfad = os.path.join(archiv_ordner, archivierte_datei_name) + + # Verschiebe die alte lawyer_details.json in den Archivordner + shutil.move(ziel_datei_pfad, archivierte_datei_pfad) + + # Kopiere die update_lawyer_details.json in den Zielordner und benenne sie um + shutil.copy(update_datei_pfad, ziel_datei_pfad) + + else: + # Wenn keine lawyer_details.json im Zielordner, kopiere diese aus dem Kundendatenordner, falls vorhanden + source_datei_pfad = os.path.join(kundendaten_ordner_app, name_der_anwalt_daten_json_datei) + if os.path.isfile(source_datei_pfad): + shutil.copy(source_datei_pfad, ziel_datei_pfad) + + +def get_temp_folder(): + temp_folder_path = os.path.join(os.path.expanduser("~"), BASE_DIR, TEMP_FOLDER) + ensure_folder_exists(temp_folder_path) + return temp_folder_path + +def get_base_dir(): + return get_base_dir_path() + +def get_template_folder(): + template_folder_path = os.path.join( + os.path.expanduser("~"), BASE_DIR, VORLAGEN_ORDNER_APP + ) + ensure_folder_exists(template_folder_path) + return template_folder_path + +def get_update_folder(): + update_folder_path = os.path.join( + os.path.expanduser("~"), BASE_DIR, UPDATE_ORDNER_NAME + ) + ensure_folder_exists(update_folder_path) + return update_folder_path + +def get_mandanten_folder(): + mandanten_folder_path = os.path.join( + os.path.expanduser("~"), BASE_DIR, MANDATEN_ORDNER_NAME + ) + ensure_folder_exists(mandanten_folder_path) + return mandanten_folder_path + +def get_temp_file_for_template_file(template_file): + source_path = os.path.join(get_template_folder(), template_file) + + if not os.path.exists(source_path): + logging.error(f"Template file does not exist: {source_path}") + raise FileNotFoundError(f"Template file does not exist: {source_path}") + + # Generate a unique temporary file name + unique_filename = f"{uuid.uuid4()}_{template_file}" + temp_file_path = os.path.join(get_temp_folder(), unique_filename) + + # Copy the template to a temporary file and return its path + try: + shutil.copyfile(source_path, temp_file_path) + return temp_file_path + except IOError as e: + logging.error(f"Failed to create a temporary file from template: {e}") + raise + + + +def print_paragraph_details(paragraph): + print("This is one paragraph:") + if paragraph.text: + print(f"Text: {paragraph.text}") + if paragraph.style: + print(f"Style: {paragraph.style.name}") + if paragraph.alignment: + print(f"Alignment: {paragraph.alignment}") + if paragraph.contains_page_break: + print(f"Contains page break: {paragraph.contains_page_break}") + if paragraph.hyperlinks: + print(f"Hyperlinks: {paragraph.hyperlinks}") + if paragraph.paragraph_format: + print("Paragraph format details:") + format = paragraph.paragraph_format + if format.alignment: + print(f" Alignment: {format.alignment}") + if format.keep_together: + print(f" Keep together: {format.keep_together}") + if format.keep_with_next: + print(f" Keep with next: {format.keep_with_next}") + if format.left_indent: + print(f" Left indent: {format.left_indent}") + if format.line_spacing: + print(f" Line spacing: {format.line_spacing}") + if format.line_spacing_rule: + print(f" Line spacing rule: {format.line_spacing_rule}") + if format.page_break_before: + print(f" Page break before: {format.page_break_before}") + if format.right_indent: + print(f" Right indent: {format.right_indent}") + if format.space_after: + print(f" Space after: {format.space_after}") + if format.space_before: + print(f" Space before: {format.space_before}") + if format.tab_stops: + print(" Tab stops:") + for tabstop in format.tab_stops: + print(f" Alignment: {tabstop.alignment}") + print(f" Leader: {tabstop.leader}") + print(f" Position: {tabstop.position}") + if format.widow_control: + print(f" Widow control: {format.widow_control}") + if paragraph.runs: + print("Runs:") + for run in paragraph.runs: + if run.text: + print(f" Text: {run.text}") + if run.bold: + print(f" Bold: {run.bold}") + if run.italic: + print(f" Italic: {run.italic}") + if run.underline: + print(f" Underline: {run.underline}") + if run.font: + if run.font.name: + print(f" Font name: {run.font.name}") + if run.font.size: + print(f" Font size: {run.font.size}") + +def datenabfrage_datev_for_aktenzeichen(aktenzeichen:str, passwort:str): + url = 'https://localhost:58452/datev/api/law/v1/files/' + params = { + 'select': 'id, name, number', + 'filter': f"file_number eq '{aktenzeichen}'", # Verwendung eines f-Strings zur Einsetzung + 'orderby': 'my_property_name desc,other_property_name asc', + 'top': '100', + 'skip': '10' + } + headers = { + 'accept': 'application/json; charset=utf-8' + } + # Ersetzen Sie 'your_username' und 'your_password' mit Ihren tatsächlichen Anmeldedaten + username = get_nutzername() + auth = HTTPBasicAuth(username, passwort) + + response = requests.get(url, params=params, headers=headers, auth=auth, verify=False) + + if response.status_code == 200: + return response.json() # Gibt das JSON-Antwortobjekt zurück + else: + return f"Error: {response.status_code}" + +def get_nutzername(): + login_information = get_login_information() + return login_information["username"] + +def set_nutzername(nutzername): + login_information = get_login_information() + login_information["username"] = nutzername + set_login_information(login_information) + +def get_datev_example_data(): + return [ + { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "file_number_short": "000001-05", + "file_number": "000001-2005/001:00", + "file_name": "Insolvenzverfahren Mustermann", + "project_number": "123/331-12", + "short_reason": "Beratung", + "long_reason": "vacnatocbosa", + "department": { + "id": "ebd93cfc-1c2e-4927-aee5-24b448b050fd", + "link": "https://localhost:58452/datev/api/law/v1/departments/ebd93cfc-1c2e-4927-aee5-24b448b050fd" + }, + "causes": [ + { + "id": "051534f8-7b78-441a-aa9e-6f708b49d855", + "number": 3, + "name": "Forderung aus Warenlieferung", + "department_id": "ebd93cfc-1c2e-4927-aee5-24b448b050fd", + "department_link": "https://localhost:58452/datev/api/law/v1/departments/ebd93cfc-1c2e-4927-aee5-24b448b050fd" + }, + { + "id": "051534f8-7b78-441a-aa9e-6f708b49d855", + "number": 15, + "name": "sonstige zivilrechtliche Ansprüche", + "department_id": "e5a91019-af4d-4373-a18c-36e64e4ec478", + "department_link": "https://localhost:58452/datev/api/law/v1/departments/e5a91019-af4d-4373-a18c-36e64e4ec478" + } + ], + "partner": { + "id": "c015c071-43c4-432f-be80-508d54c720e7", + "number": 62, + "display_name": "Ernst Exempeladvokat", + "link": "https://localhost:58452/datev/api/law/v1/employees/c015c071-43c4-432f-be80-508d54c720e7" + }, + "case_handlers": [ + { + "id": "c015c071-43c4-432f-be80-508d54c720e7", + "number": 62, + "display_name": "Ernst Exempeladvokat", + "primary_case_handler": true, + "commission": 100, + "employee_id": "f8586db2-4f22-44af-8cec-16f426bd5440", + "employee_link": "http://localhost:58454/datev/api/master-data/v1/employees/f8586db2-4f22-44af-8cec-16f426bd5440" + } + ], + "security_zone": { + "id": "174ddc49-e8c4-466b-8c35-d8eef5d655b6", + "short_name": "SB-0", + "name": "Öffentliche Akten" + }, + "establishment": { + "number": 1, + "name": "Musterniederlassung", + "link": "http://localhost:58454/datev/api/master-data/v1/corporate-structures/3fa85f64-5717-4562-b3fc-2c963f66afa6/establishments/59bb1870-5e0a-4ce9-bb7d-42e95f5cdb4e", + "organization": { + "id": "2da7f880-6c24-44cd-be38-32746a268b0f", + "number": 1, + "name": "Musterkanzlei", + "link": "http://localhost:58454/datev/api/master-data/v1/corporate-structures/3fa85f64-5717-4562-b3fc-2c963f66afa6" + } + }, + "economic_data": { + "cause_value": { + "amount": 20000, + "currency": "EUR" + }, + "budget": { + "amount": 10000, + "currency": "EUR" + }, + "budget_timespan": "total", + "base_currency": "EUR" + }, + "accounting_area": { + "id": "7447f931-b42e-4e71-84f3-1319a49fb076", + "number": 1, + "name": "Standardbuchungskreis", + "link": "https://localhost:58452/datev/api/law/v1/accounting-areas/7447f931-b42e-4e71-84f3-1319a49fb076" + }, + "reactivated": false, + "filing": { + "date": "2019-08-12", + "number": "000001-2005", + "retention_period_end": "2029-08-12", + "location": "Keller" + }, + "note": "umamonabp", + "created": { + "date": "2018-09-27", + "creator": "Ernst Exempeladvokat" + }, + "modified": { + "date": "2019-08-11", + "creator": "Ernst Exempeladvokat" + } + }, + { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "file_number_short": "000001-05", + "file_number": "000001-2005/001:00", + "file_name": "Insolvenzverfahren Mustermann", + "project_number": "123/331-12", + "short_reason": "Beratung", + "long_reason": "morigejofo", + "department": { + "id": "ebd93cfc-1c2e-4927-aee5-24b448b050fd", + "link": "https://localhost:58452/datev/api/law/v1/departments/ebd93cfc-1c2e-4927-aee5-24b448b050fd" + }, + "causes": [ + { + "id": "051534f8-7b78-441a-aa9e-6f708b49d855", + "number": 3, + "name": "Forderung aus Warenlieferung", + "department_id": "ebd93cfc-1c2e-4927-aee5-24b448b050fd", + "department_link": "https://localhost:58452/datev/api/law/v1/departments/ebd93cfc-1c2e-4927-aee5-24b448b050fd" + }, + { + "id": "051534f8-7b78-441a-aa9e-6f708b49d855", + "number": 15, + "name": "sonstige zivilrechtliche Ansprüche", + "department_id": "e5a91019-af4d-4373-a18c-36e64e4ec478", + "department_link": "https://localhost:58452/datev/api/law/v1/departments/e5a91019-af4d-4373-a18c-36e64e4ec478" + } + ], + "partner": { + "id": "c015c071-43c4-432f-be80-508d54c720e7", + "number": 62, + "display_name": "Ernst Exempeladvokat", + "link": "https://localhost:58452/datev/api/law/v1/employees/c015c071-43c4-432f-be80-508d54c720e7" + }, + "case_handlers": [ + { + "id": "c015c071-43c4-432f-be80-508d54c720e7", + "number": 62, + "display_name": "Ernst Exempeladvokat", + "primary_case_handler": true, + "commission": 100, + "employee_id": "f8586db2-4f22-44af-8cec-16f426bd5440", + "employee_link": "http://localhost:58454/datev/api/master-data/v1/employees/f8586db2-4f22-44af-8cec-16f426bd5440" + } + ], + "security_zone": { + "id": "174ddc49-e8c4-466b-8c35-d8eef5d655b6", + "short_name": "SB-0", + "name": "Öffentliche Akten" + }, + "establishment": { + "number": 1, + "name": "Musterniederlassung", + "link": "http://localhost:58454/datev/api/master-data/v1/corporate-structures/3fa85f64-5717-4562-b3fc-2c963f66afa6/establishments/59bb1870-5e0a-4ce9-bb7d-42e95f5cdb4e", + "organization": { + "id": "2da7f880-6c24-44cd-be38-32746a268b0f", + "number": 1, + "name": "Musterkanzlei", + "link": "http://localhost:58454/datev/api/master-data/v1/corporate-structures/3fa85f64-5717-4562-b3fc-2c963f66afa6" + } + }, + "economic_data": { + "cause_value": { + "amount": 20000, + "currency": "EUR" + }, + "budget": { + "amount": 10000, + "currency": "EUR" + }, + "budget_timespan": "total", + "base_currency": "EUR" + }, + "accounting_area": { + "id": "7447f931-b42e-4e71-84f3-1319a49fb076", + "number": 1, + "name": "Standardbuchungskreis", + "link": "https://localhost:58452/datev/api/law/v1/accounting-areas/7447f931-b42e-4e71-84f3-1319a49fb076" + }, + "reactivated": false, + "filing": { + "date": "2019-08-12", + "number": "000001-2005", + "retention_period_end": "2029-08-12", + "location": "Keller" + }, + "note": "supvujsekdiras", + "created": { + "date": "2018-09-27", + "creator": "Ernst Exempeladvokat" + }, + "modified": { + "date": "2019-08-11", + "creator": "Ernst Exempeladvokat" + } + }, + { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "file_number_short": "000001-05", + "file_number": "000001-2005/001:00", + "file_name": "Insolvenzverfahren Mustermann", + "project_number": "123/331-12", + "short_reason": "Beratung", + "long_reason": "tanejomeve", + "department": { + "id": "ebd93cfc-1c2e-4927-aee5-24b448b050fd", + "link": "https://localhost:58452/datev/api/law/v1/departments/ebd93cfc-1c2e-4927-aee5-24b448b050fd" + }, + "causes": [ + { + "id": "051534f8-7b78-441a-aa9e-6f708b49d855", + "number": 3, + "name": "Forderung aus Warenlieferung", + "department_id": "ebd93cfc-1c2e-4927-aee5-24b448b050fd", + "department_link": "https://localhost:58452/datev/api/law/v1/departments/ebd93cfc-1c2e-4927-aee5-24b448b050fd" + }, + { + "id": "051534f8-7b78-441a-aa9e-6f708b49d855", + "number": 15, + "name": "sonstige zivilrechtliche Ansprüche", + "department_id": "e5a91019-af4d-4373-a18c-36e64e4ec478", + "department_link": "https://localhost:58452/datev/api/law/v1/departments/e5a91019-af4d-4373-a18c-36e64e4ec478" + } + ], + "partner": { + "id": "c015c071-43c4-432f-be80-508d54c720e7", + "number": 62, + "display_name": "Ernst Exempeladvokat", + "link": "https://localhost:58452/datev/api/law/v1/employees/c015c071-43c4-432f-be80-508d54c720e7" + }, + "case_handlers": [ + { + "id": "c015c071-43c4-432f-be80-508d54c720e7", + "number": 62, + "display_name": "Ernst Exempeladvokat", + "primary_case_handler": true, + "commission": 100, + "employee_id": "f8586db2-4f22-44af-8cec-16f426bd5440", + "employee_link": "http://localhost:58454/datev/api/master-data/v1/employees/f8586db2-4f22-44af-8cec-16f426bd5440" + } + ], + "security_zone": { + "id": "174ddc49-e8c4-466b-8c35-d8eef5d655b6", + "short_name": "SB-0", + "name": "Öffentliche Akten" + }, + "establishment": { + "number": 1, + "name": "Musterniederlassung", + "link": "http://localhost:58454/datev/api/master-data/v1/corporate-structures/3fa85f64-5717-4562-b3fc-2c963f66afa6/establishments/59bb1870-5e0a-4ce9-bb7d-42e95f5cdb4e", + "organization": { + "id": "2da7f880-6c24-44cd-be38-32746a268b0f", + "number": 1, + "name": "Musterkanzlei", + "link": "http://localhost:58454/datev/api/master-data/v1/corporate-structures/3fa85f64-5717-4562-b3fc-2c963f66afa6" + } + }, + "economic_data": { + "cause_value": { + "amount": 20000, + "currency": "EUR" + }, + "budget": { + "amount": 10000, + "currency": "EUR" + }, + "budget_timespan": "total", + "base_currency": "EUR" + }, + "accounting_area": { + "id": "7447f931-b42e-4e71-84f3-1319a49fb076", + "number": 1, + "name": "Standardbuchungskreis", + "link": "https://localhost:58452/datev/api/law/v1/accounting-areas/7447f931-b42e-4e71-84f3-1319a49fb076" + }, + "reactivated": false, + "filing": { + "date": "2019-08-12", + "number": "000001-2005", + "retention_period_end": "2029-08-12", + "location": "Keller" + }, + "note": "tuhoweswurisa", + "created": { + "date": "2018-09-27", + "creator": "Ernst Exempeladvokat" + }, + "modified": { + "date": "2019-08-11", + "creator": "Ernst Exempeladvokat" + } + } + ] + +def hinzufuegen_anwaltsdaten_zum_kontext(kontext, anwalt_json=None): + + if anwalt_json is None: + anwalt_json = get_lawyer_data() + + # Hier werden die Anwaltsdetails aus der anwalt_json extrahiert + anwalt_details = anwalt_json.get('lawyer_details', {}) + kontext['ANWÄLTE'] = [ + { + 'NAME': details.get('name', ''), + 'FACHGEBIETE': details.get('specialty', '').split('; ') if details.get('specialty') else [] + } + for anwalt_id, details in anwalt_details.items() + ] + return kontext + + + +def add_ausfuehrung(reference, kundenprogramm_ID, antrags_name): + ensure_data_file_exists() + new_ausfuehrung = { + "id": str(uuid.uuid4()), + "reference": reference, + "kundenprogramm_ID": kundenprogramm_ID, + "datum": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "antrags_name": antrags_name, + "fehlerhaft": False + } + with open(get_ausfuehrungen_file_path(), "r+") as file: + data = json.load(file) + data.append(new_ausfuehrung) + file.seek(0) + json.dump(data, file, indent=4) + +def mark_ausfuehrung_as_fehlerhaft(ausfuehrung_id): + ensure_data_file_exists() + with open(get_ausfuehrungen_file_path(), "r+") as file: + data = json.load(file) + for ausfuehrung in data: + if ausfuehrung["id"] == ausfuehrung_id: + ausfuehrung["fehlerhaft"] = True + break + file.seek(0) + file.truncate() + json.dump(data, file, indent=4) + + +def open_file(file_path): + if file_path: + try: + if platform.system() == "Windows": + subprocess.run(["explorer", file_path], check=True) + elif platform.system() == "Darwin": # macOS + subprocess.run(["open", file_path], check=True) + else: # Assuming Linux + subprocess.run(["xdg-open", file_path], check=True) + except subprocess.CalledProcessError as e: + print(f"Error opening file: {e}") + else: + print("File path is not set. Unable to open file.") + +def get_help_file_path(app): + return os.path.join(app.paths.app, "resources", "help.pdf") + +def get_updates_datei_user(): + #ich möchte den dateipfad der update.json datei aus dem updates ordner haben, welcher im updates ordner im user verzeichnis liegt + updates_dateipfad_user = os.path.join(os.path.expanduser("~"), get_base_dir(), UPDATE_ORDNER_NAME_USER, "update.json") + return updates_dateipfad_user + +def get_updates_pdf_path(app): + updates_pdf_dateipfad = os.path.join(app.paths.app, "resources", "update.pdf") + return updates_pdf_dateipfad + +def update_daten_laden_user(): + file_path = get_updates_datei_user() + with open(file_path, "r") as f: + return json.load(f) + +def update_daten_laden_app(app): + file_path = get_updates_datei_app(app) + with open(file_path, "r") as f: + return json.load(f) + +def get_updates_datei_app(app): + updates_datei_app = os.path.join(app.paths.app, "resources", UPDATE_ORDNER_NAME_APP, "update.json") + return updates_datei_app + +def update_in_updates_ordner_uebertragen(app): + updates_datei_app = os.path.join(app.paths.app, "resources", UPDATE_ORDNER_NAME_APP, "update.json") + updates_datei_user = get_updates_datei_user() + + shutil.copy(updates_datei_app, updates_datei_user) + +def versionsordner_erstellen(): + folder_name = UPDATE_ORDNER_NAME_USER + ensure_folder_exists(folder_name) \ No newline at end of file diff --git a/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/utils.py b/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/utils.py index eb9380d..774d607 100644 --- a/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/utils.py +++ b/{{ cookiecutter.app_name }}/src/{{ cookiecutter.module_name }}/utils.py @@ -3,6 +3,7 @@ import subprocess import platform from {{ cookiecutter.app_name|lower|replace('-', '_') }}.CONSTANTS import BASE_DIR, SETTINGS_ORDNER + def ensure_folder_exists(folder_name): base_dir = get_base_dir_path() folder_path = os.path.join(base_dir, folder_name) @@ -188,7 +189,467 @@ def is_libreoffice_installed(): except (subprocess.CalledProcessError, FileNotFoundError): return False -def get_settings_file_path(): - settings_folder = ensure_folder_exists(SETTINGS_ORDNER) - settings_file = os.path.join(settings_folder, "settings.json") - return settings_file +#Law + + import json +import os +import uuid +from nadoo_law.CONSTANTS import ( + BEWEISMITTEL_OWI_DATA_FILE_NAME, + BEWEISMITTEL_SCHEIDUNG_DATA_FILE_NAME, + LAWYER_DATA_FILE_NAME, + BASE_DIR, + LOGIN_INFORMATION_FILE_NAME, + AUSFÜHRUNGEN_DATEI_NAME +) + + +def get_lawyer_data_file_path(): + base_dir = get_base_dir_path() + return os.path.join(base_dir, LAWYER_DATA_FILE_NAME) + + +def get_beweismittel_OWi_data_file_path(): + base_dir = get_base_dir_path() + return os.path.join(base_dir, BEWEISMITTEL_OWI_DATA_FILE_NAME) + +def get_beweismittel_Scheidung_data_file_path(): + base_dir = get_base_dir_path() + return os.path.join(base_dir, BEWEISMITTEL_SCHEIDUNG_DATA_FILE_NAME) + +def get_base_dir_path(): + ensure_base_folder_exits() + return os.path.join(os.path.expanduser("~"), BASE_DIR) + +def ensure_folder_exists(folder_name): + base_dir = get_base_dir_path() + folder_path = os.path.join(base_dir, folder_name) + if not os.path.exists(folder_path): + os.makedirs(folder_path) + return folder_path + +def ensure_base_folder_exits(): + base_dir = os.path.join(os.path.expanduser("~"), BASE_DIR) + if not os.path.exists(base_dir): + os.makedirs(base_dir) + +def ensure_lawyer_data_file_exists(): + file_path = get_lawyer_data_file_path() + if not os.path.isfile(file_path): + # Initialize the file with a dummy lawyer if it doesn't exist + dummy_data = { + "selected_lawyer_id": str(uuid.uuid4()), + "lawyer_details": { + "dummy_id": { + "name": "Dummy Lawyer", + "email": "dummy@lawfirm.com", + "phone": "123-456-7890", + "fax": "098-765-4321", + "title": "Lawyer", + "specialty": "General", + } + }, + } + with open(file_path, "w") as f: + json.dump(dummy_data, f, indent=4) + + +def ensure_beweismittel_OWi_data_file_exists(): + file_path = get_beweismittel_OWi_data_file_path() + if not os.path.isfile(file_path): + # Initialize the file with default data if it doesn't exist + default_data = { + "options": [ + "Messprotokolle", + "Ausbildungsnachweise der Mess- und Auswertebeamten", + "Originalbeweisfotos", + "Eichscheine", + "Gesamte Messreihe vom Tattag", + "Digitale Rohmessdaten sowie die dazugehörigen öff. Token und Passwörter", + "Statistikdatei mit Case List", + "Konformitätsbescheinigung und –erklärung zum Messgerät", + "Kalibrier- und Testfotos", + "Bedienungsanleitung der zum Tattag gültigen Version", + "Auskunft über Reparaturen, Wartungen, vorgezogene Neueichung oder vgl. die Funktionsfähigkeit des hier verwendeten Messgerätes berührende Ereignisse", + "Beschilderungsnachweise für 2 km vor und nach der Messstelle", + "Liste aller am Tattag aufgenommenen Verkehrsverstöße", + ] + + + } + with open(file_path, "w") as f: + json.dump(default_data, f, indent=4) + +def ensure_beweismittel_Scheidung_data_file_exists(): + file_path = get_beweismittel_Scheidung_data_file_path() + if not os.path.isfile(file_path): + # Initialize the file with default data if it doesn't exist + default_data = { + "options": [ + "Geburtsurkunde", + "Scheidungsfolgevereinbarung", + ] + } + with open(file_path, "w") as f: + json.dump(default_data, f, indent=4) + +def ensure_user_auth_data_file_exists(): + file_path = get_user_auth_data_file_path() + if not os.path.isfile(file_path): + # Initialize the file with default data if it doesn't exist + default_data = { + "user_name": "", + } + with open(file_path, "w") as f: + json.dump(default_data, f, indent=4) + +def get_user_auth_data_file_path(): + base_dir = os.path.join(os.path.expanduser("~"), BASE_DIR) + if not os.path.exists(base_dir): + os.makedirs(base_dir) + return os.path.join(base_dir, "user_auth_data.json") + +def get_login_information_test(): + login_information = { + "username": "test", + } + return login_information + +def get_login_information(): + ensure_login_information_file_exists() + file_path = get_login_information_file_path() + with open(file_path, "r") as f: + return json.load(f) + + +def get_login_information_file_path(): + base_dir_path = get_base_dir_path() + return os.path.join(base_dir_path, LOGIN_INFORMATION_FILE_NAME) + +def get_ausfuehrungen_file_path(): + base_dir_path = get_base_dir_path() + return os.path.join(base_dir_path, AUSFÜHRUNGEN_DATEI_NAME) + + +def ensure_login_information_file_exists(): + file_path = get_login_information_file_path() + if not os.path.isfile(file_path): + # Initialize the file with a dummy lawyer if it doesn't exist + dummy_data = { + "username": "Bitte DATEV-Nutzername eingeben", + } + with open(file_path, "w") as f: + json.dump(dummy_data, f, indent=4) + + +def set_login_information(login_information): + ensure_login_information_file_exists() + file_path = get_login_information_file_path() + with open(file_path, "w") as f: + json.dump(login_information, f, indent=4) + +def ensure_data_file_exists(): + file_path = get_ausfuehrungen_file_path() + if not os.path.isfile(file_path): + with open(file_path, "w") as file: + json.dump([], file) + +#LaunchPad + +import os +import platform +import re +import unicodedata +import subprocess +from briefcase.exceptions import ( + InvalidTemplateRepository, + NetworkFailure, + TemplateUnsupportedVersion, + BriefcaseCommandError, +) +from cookiecutter import exceptions as cookiecutter_exceptions +from cookiecutter.main import cookiecutter +from cookiecutter.repository import is_repo_url +from pathlib import Path +import toga +import toml + +cookiecutter = staticmethod(cookiecutter) + +def make_app_name(formal_name): + """Construct a candidate app name from a formal name. + + :param formal_name: The formal name + :returns: The candidate app name + """ + normalized = unicodedata.normalize("NFKD", formal_name) + stripped = re.sub("[^0-9a-zA-Z_]+", "", normalized).lstrip("_") + if stripped: + return stripped.lower() + else: + # If stripping removes all the content, + # use a dummy app name as the suggestion. + return "myapp" + + +def make_module_name(app_name): + """Construct a valid module name from an app name. + + :param app_name: The app name + :returns: The app's module name. + """ + return app_name.replace("-", "_") + + +def generate_template(template, branch, output_path, extra_context): + """Ensure the named template is up-to-date for the given branch, and roll out + that template. + + :param template: The template URL or path to generate + :param branch: The branch of the template to use + :param output_path: The filesystem path where the template will be generated. + :param extra_context: Extra context to pass to the cookiecutter template + """ + # Make sure we have an updated cookiecutter template, + # checked out to the right branch + cached_template = update_cookiecutter_cache(template=template, branch=branch) + + try: + # Unroll the template + cookiecutter( + str(cached_template), + no_input=True, + output_dir=str(output_path), + checkout=branch, + extra_context=extra_context, + ) + except subprocess.CalledProcessError as e: + # Computer is offline + # status code == 128 - certificate validation error. + raise NetworkFailure("clone template repository") from e + except cookiecutter_exceptions.RepositoryNotFound as e: + # Either the template path is invalid, + # or it isn't a cookiecutter template (i.e., no cookiecutter.json) + raise InvalidTemplateRepository(template) from e + except cookiecutter_exceptions.RepositoryCloneFailed as e: + # Branch does not exist. + raise TemplateUnsupportedVersion(branch) from e + + +def update_cookiecutter_cache(template: str, branch="master"): + """Ensure that we have a current checkout of a template path. + + If the path is a local path, use the path as is. + + If the path is a URL, look for a local cache; if one exists, update it, + including checking out the required branch. + + :param template: The template URL or path. + :param branch: The template branch to use. Default: ``master`` + :return: The path to the cached template. This may be the originally + provided path if the template was a file path. + """ + if is_repo_url(template): + # The app template is a repository URL. + # + # When in `no_input=True` mode, cookiecutter deletes and reclones + # a template directory, rather than updating the existing repo. + # + # Look for a cookiecutter cache of the template; if one exists, + # try to update it using git. If no cache exists, or if the cache + # directory isn't a git directory, or git fails for some reason, + # fall back to using the specified template directly. + cached_template = cookiecutter_cache_path(template) + try: + repo = self.tools.git.Repo(cached_template) + # Raises ValueError if "origin" isn't a valid remote + remote = repo.remote(name="main") + try: + # Attempt to update the repository + remote.fetch() + except self.tools.git.exc.GitCommandError as e: + # We are offline, or otherwise unable to contact + # the origin git repo. It's OK to continue; but + # capture the error in the log and warn the user + # that the template may be stale. + pass + + try: + # Check out the branch for the required version tag. + head = remote.refs[branch] + + self.logger.info( + f"Using existing template (sha {head.commit.hexsha}, " + f"updated {head.commit.committed_datetime.strftime('%c')})" + ) + head.checkout() + except IndexError as e: + # No branch exists for the requested version. + raise TemplateUnsupportedVersion(branch) from e + except self.tools.git.exc.NoSuchPathError: + # Template cache path doesn't exist. + # Just use the template directly, rather than attempting an update. + cached_template = template + except self.tools.git.exc.InvalidGitRepositoryError: + # Template cache path exists, but isn't a git repository + # Just use the template directly, rather than attempting an update. + cached_template = template + except ValueError as e: + raise BriefcaseCommandError( + f"Git repository in a weird state, delete {cached_template} and try briefcase create again" + ) from e + else: + # If this isn't a repository URL, treat it as a local directory + cached_template = template + + return cached_template + + +def cookiecutter_cache_path(template): + """Determine the cookiecutter template cache directory given a template URL. + + This will return a valid path, regardless of whether `template` + + :param template: The template to use. This can be a filesystem path or + a URL. + :returns: The path that cookiecutter would use for the given template name. + """ + template = template.rstrip("/") + tail = template.split("/")[-1] + cache_name = tail.rsplit(".git")[0] + return Path.home() / ".cookiecutters" / cache_name + +def update_ui(self:toga.App): + # Refresh the UI to show changes + self.main_window.content = self.new_project_form + +def set_installation_state(app:toga.App): + config_path = app.paths.config / "install_state.toml" + + # Ensure the directory exists + config_path.parent.mkdir(parents=True, exist_ok=True) + + # Check if the file exists + if not config_path.exists(): + # If not, create it with the initial 'installed' state + config_data = {"installed": True} + else: + # If it exists, load the existing data + with open(config_path, "r") as config_file: + config_data = toml.load(config_file) + + # Update the 'installed' state to True + config_data["installed"] = True + + # Save the updated data + with open(config_path, "w") as config_file: + toml.dump(config_data, config_file) + +def update_ui_post_install(self:toga.App): + # Remove the 'Install' button and add the 'New Project' button + self.main_box.remove(self.install_btn) + +def install_python_with_pyenv(): + # Check if the Python version already exists + pyenv_version_exists = ( + subprocess.run( + ["pyenv", "versions", "--bare", "--skip-aliases", "3.11.7"], + capture_output=True, + ).returncode + == 0 + ) + + # If the version exists, skip installation + if not pyenv_version_exists: + # Use 'yes' to automatically answer 'y' to any prompts + subprocess.run("yes | pyenv install 3.11.7", shell=True) + else: + print("Python 3.11.7 is already installed.") + + # Set global version + subprocess.run(["pyenv", "global", "3.11.7"]) + +def install_pyenv(): + # Example command, adjust based on OS + subprocess.run(["curl", "-L", "https://pyenv.run", "|", "bash"]) + # Additional commands may be needed to integrate pyenv into the shell + +def setup_project_folder(): + # Get the current user's home directory and set the project folder path + project_folder = get_project_folder_path() + return project_folder + +def get_project_folder_path(): + home_dir = os.path.expanduser("~") + project_folder = os.path.join(home_dir, "Documents", "GitHub") + + # Create the folder if it doesn't exist + if not os.path.exists(project_folder): + os.makedirs(project_folder) + + return project_folder + +def create_and_activate_venv(self): + os_type = platform.system() + if os_type == "Darwin": # macOS + return self.create_and_activate_venv_mac() + # Add more conditions for other OS types here + else: + print(f"OS {os_type} not supported yet") + +def create_and_activate_venv_mac(self): + python_path = ( + subprocess.check_output(["pyenv", "which", "python"]).decode().strip() + ) + # Create the virtual environment inside the project folder + venv_path = os.path.join(get_project_folder_path(), "env") + subprocess.run([python_path, "-m", "venv", venv_path]) + # Activate the virtual environment - for macOS + activate_command = f"source {venv_path}/bin/activate" + subprocess.run(["bash", "-c", activate_command]) + + return venv_path + +def on_new_developer_name_entered(self, widget): + # Generate the email based on the entered name + new_name = widget.value + if new_name: + new_email = f"{new_name.replace(' ', '.').lower()}@nadooit.de" + self.author_email_input.value = new_email + +def create_pyproject_file(self, user_data, project_folder): + # Construct the path to the template file + template_file_name = "base_project_template.toml" + template_path = Path(self.app.paths.app / "resources" / template_file_name) + + # Ensure the project subfolder exists + project_subfolder = Path(project_folder, user_data["app_name"]) + project_subfolder.mkdir(parents=True, exist_ok=True) + + # New project file path + new_project_path = project_subfolder / "pyproject.toml" + + try: + with open(template_path, "r") as template_file: + template_content = template_file.read() + + # Replace placeholders with actual data + for key, value in user_data.items(): + placeholder = "{{" + key.upper() + "}}" + template_content = template_content.replace(placeholder, value) + + print(template_content) + + # Write the new pyproject.toml file + with open(new_project_path, "w") as new_project_file: + new_project_file.write(template_content) + + return new_project_file + + except FileNotFoundError as e: + self.display_error(f"Template file not found: {e}") + except IOError as e: + self.display_error(f"Error while handling the file: {e}") + except Exception as e: + self.display_error(f"An unexpected error occurred: {e}") + \ No newline at end of file