lexoffice.py added

This commit is contained in:
Isaak Buslovich 2024-01-30 19:01:26 +01:00
parent 8bef4f81e0
commit 59ca900a14
8 changed files with 96 additions and 11 deletions

2
.gitignore vendored
View File

@ -294,3 +294,5 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk
# Sensitive details
config.yaml

View File

@ -1,2 +1,2 @@
Rechnungsnummer;Email;Anrede
RE357891;isaak.buslovich@trocknerheld.de;Isaak Trocknerheld
RE255111;fws-rs@vielhuber.eu;Sehr geehrter Herr Vielhuber

1 Rechnungsnummer Email Anrede
2 RE357891 RE255111 isaak.buslovich@trocknerheld.de fws-rs@vielhuber.eu Isaak Trocknerheld Sehr geehrter Herr Vielhuber

58
app/lexoffice.py Normal file
View File

@ -0,0 +1,58 @@
"""
Module: lexoffice.py
Description: Provides an interface to interact with the Lexoffice API.
This module enables operations such as retrieving invoice details from Lexoffice,
making it easier to integrate Lexoffice API functionality into a Flask application.
"""
from pathlib import Path
import yaml
import requests
import logging
class LexofficeAPI:
"""Class to handle interactions with the Lexoffice API."""
def __init__(self):
"""Initialize with the Lexoffice API access token from a config file."""
self.base_url = "https://api.lexoffice.io/v1"
self.headers = {
"Authorization": f"Bearer {self._load_api_token()}",
"Content-Type": "application/json",
"Accept": "application/json"
}
@staticmethod
def _load_api_token() -> str:
"""Load the API token from the config.yaml file."""
config_path = Path(__file__).parent.parent / 'config.yaml'
with config_path.open('r') as file:
config = yaml.safe_load(file)
return config['lexoffice']['api_token']
def get_invoice_total_gross_amount(self, invoice_id: str) -> float:
"""
Retrieve the total gross amount for a specific invoice.
Args:
invoice_id (str): Unique identifier of the invoice.
Returns:
float or None: Total gross amount of the invoice, or None if an error occurs.
"""
url = f"{self.base_url}/invoices/{invoice_id}"
try:
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json().get('totalPrice', {}).get('totalGrossAmount')
except requests.exceptions.RequestException as e:
logging.error(f"Error fetching invoice: {e}")
return None
# Usage example:
# lexoffice_api = LexofficeAPI()
# total_gross_amount = lexoffice_api.get_invoice_total_gross_amount('your_invoice_id')
# print(total_gross_amount)

View File

@ -1,8 +1,10 @@
from flask import render_template, redirect, url_for, current_app, render_template_string, request
import os
import csv
from app import app, htmx
import logging
from app.lexoffice import LexofficeAPI
def read_invoices_from_csv(csv_file_path):
@ -10,9 +12,10 @@ def read_invoices_from_csv(csv_file_path):
with open(csv_file_path, mode='r', encoding='utf-8') as file:
return list(csv.DictReader(file, delimiter=';'))
except FileNotFoundError:
current_app.logger.error(f"CSV file not found at {csv_file_path}")
logging.error(f"CSV file not found at {csv_file_path}")
return []
except csv.Error as e:
current_app.logger.error(f"Error reading CSV file: {e}")
logging.error(f"Error reading CSV file: {e}")
return []
@ -48,31 +51,46 @@ def buchhaltung():
@app.route('/add-invoice', methods=['POST'])
def add_invoice():
csv_file_path = os.path.join(current_app.root_path, 'data', 'invoices.csv')
# Extract invoice data from form
new_invoice = {
'Rechnungsnummer': request.form['rechnungsnummer'],
'Email': request.form['email'],
'Anrede': request.form['anrede']
'Anrede': request.form['anrede'],
# Initialize 'Betrag' with a placeholder (to be updated)
'Betrag': 'N/A'
}
try:
# Read the existing data
# Fetch the total gross amount for the new invoice using LexofficeAPI
lexoffice_api = LexofficeAPI('your_access_token') # Replace with actual access token
total_gross_amount = lexoffice_api.get_invoice_total_gross_amount(new_invoice['Rechnungsnummer'])
# Update 'Betrag' in the new invoice data
if total_gross_amount is not None:
new_invoice['Betrag'] = total_gross_amount
# Read existing data from CSV
with open(csv_file_path, 'r', newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
fieldnames = reader.fieldnames
if 'Betrag' not in fieldnames:
fieldnames.append('Betrag')
existing_data = list(reader)
# Add the new invoice at the beginning of the data
existing_data.insert(0, new_invoice)
# Write the updated data back to the file
# Write the updated data back to the CSV file
with open(csv_file_path, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=';')
writer.writeheader()
writer.writerows(existing_data)
return redirect(url_for('buchhaltung'))
except Exception as e:
current_app.logger.error(f"Error updating CSV file: {e}")
logging.error(f"Error updating CSV file: {e}")
return "An error occurred while adding the invoice", 500

View File

@ -1,5 +1,5 @@
/* Import Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
/* Root and Variable Definitions */
:root {
@ -17,7 +17,7 @@
/* Body and Global Styles */
body {
font-family: 'Roboto', sans-serif;
font-family: 'Inter', sans-serif;
margin: 0;
padding: 0;
background: var(--light-grey);

View File

@ -5,6 +5,7 @@
<th>Rechnungsnummer</th>
<th>Email</th>
<th>Anrede</th>
<th>Betrag</th>
</tr>
</thead>
<tbody>
@ -13,6 +14,7 @@
<td>{{ invoice['Rechnungsnummer'] }}</td>
<td>{{ invoice['Email'] }}</td>
<td>{{ invoice['Anrede'] }}</td>
<td>{{ invoice['Betrag'] }}</td>
</tr>
{% endfor %}
</tbody>

View File

@ -1 +1,3 @@
flask~=2.2.5
requests~=2.25.1
pyyaml~=6.0.1

3
run.py
View File

@ -1,4 +1,7 @@
import logging
from app import app
if __name__ == '__main__':
logging.basicConfig(filename='app.log', level=logging.DEBUG,
format='%(asctime)s %(levelname)s %(name)s : %(message)s')
app.run(debug=True)