import getpass import hashlib import json import os from datetime import datetime DATA_FILE = "invoice_data.json" INVOICE_FOLDER = "invoices" def hash_password(password: str) -> str: return hashlib.sha256(password.encode("utf-8")).hexdigest() def prompt_non_empty(prompt: str) -> str: while True: value = input(prompt).strip() if value: return value print("Pole nie moze byc puste.") def prompt_positive_float(prompt: str) -> float: while True: raw_value = input(prompt).replace(",", ".").strip() try: value = float(raw_value) except ValueError: print("Wprowadz liczbe.") continue if value <= 0: print("Wartosc musi byc wieksza od zera.") continue return value def load_data(): if not os.path.exists(DATA_FILE): return None with open(DATA_FILE, "r", encoding="utf-8") as handle: return json.load(handle) def save_data(data) -> None: with open(DATA_FILE, "w", encoding="utf-8") as handle: json.dump(data, handle, indent=2, ensure_ascii=False) def run_setup(): print("=== Konfiguracja konta przedsiebiorcy ===") business = { "company_name": prompt_non_empty("Nazwa firmy: "), "owner_name": prompt_non_empty("Imie i nazwisko wlasciciela: "), "address": prompt_non_empty("Adres: "), "tax_id": prompt_non_empty("NIP: "), "bank_account": prompt_non_empty("Numer konta bankowego: "), } print("\nUstaw haslo do logowania.") while True: password = getpass.getpass("Haslo: ") confirm = getpass.getpass("Powtorz haslo: ") if not password: print("Haslo nie moze byc puste.") continue if password != confirm: print("Hasla nie sa identyczne. Sprobuj ponownie.") continue break data = { "business": business, "password_hash": hash_password(password), "invoices": [], } save_data(data) print("\nDane zapisane. Uruchom aplikacje ponownie, aby zalogowac sie i wystawiac faktury.") def authenticate(data) -> bool: for attempt in range(3): password = getpass.getpass("Haslo: ") if hash_password(password) == data["password_hash"]: return True print("Nieprawidlowe haslo.") return False def prompt_client_details(): answer = input("Dodac dane klienta? (T/N): ").strip().lower() if answer not in ("t", "tak"): return {} print("\n=== Dane klienta ===") client = { "name": prompt_non_empty("Nazwa / Imie i nazwisko: "), "address": prompt_non_empty("Adres: "), "tax_id": input("NIP (opcjonalnie): ").strip(), } return client def format_invoice_text(invoice_id: str, business: dict, invoice: dict) -> str: lines = [ f"Faktura: {invoice_id}", f"Data wystawienia: {invoice['issued_at']}", "", "=== Sprzedawca ===", f"Nazwa: {business['company_name']}", f"Wlasciciel: {business['owner_name']}", f"Adres: {business['address']}", f"NIP: {business['tax_id']}", f"Konto bankowe: {business['bank_account']}", "", "=== Nabywca ===", ] client = invoice.get("client", {}) if client: lines.extend( [ f"Nazwa: {client.get('name', '')}", f"Adres: {client.get('address', '')}", f"NIP: {client.get('tax_id', '') or '---'}", ] ) else: lines.append("Brak danych klienta (pole opcjonalne).") lines.extend( [ "", "=== Pozycja ===", f"Opis: {invoice['item_description']}", f"Ilosc: {invoice['quantity']}", f"Cena jednostkowa: {invoice['unit_price']:.2f} PLN", f"Wartosc netto: {invoice['net_total']:.2f} PLN", ] ) return "\n".join(lines) def create_invoice(data): print("\n=== Wystaw fakture ===") description = prompt_non_empty("Opis uslugi / towaru: ") quantity = prompt_positive_float("Ilosc: ") unit_price = prompt_positive_float("Cena jednostkowa (PLN): ") client = prompt_client_details() issued_at = datetime.now().strftime("%Y-%m-%d %H:%M") invoice_id = datetime.now().strftime("FV-%Y%m%d-%H%M%S") net_total = quantity * unit_price invoice = { "invoice_id": invoice_id, "issued_at": issued_at, "item_description": description, "quantity": quantity, "unit_price": unit_price, "net_total": net_total, "client": client, } os.makedirs(INVOICE_FOLDER, exist_ok=True) invoice_path = os.path.join(INVOICE_FOLDER, f"{invoice_id}.txt") with open(invoice_path, "w", encoding="utf-8") as handle: handle.write(format_invoice_text(invoice_id, data["business"], invoice)) data["invoices"].append(invoice) save_data(data) print(f"\nFaktura zapisana do {invoice_path}") print(f"Suma do zaplaty: {net_total:.2f} PLN") def main(): data = load_data() if data is None: run_setup() return print("=== Logowanie ===") if not authenticate(data): print("Zbyt wiele nieudanych prob logowania. Zakonczono.") return create_invoice(data) if __name__ == "__main__": main()