Initial commit – AufmaßCreater v2.35

This commit is contained in:
2026-06-10 11:03:43 +02:00
commit 84c933ea9c
2823 changed files with 490495 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, flash
from flask_login import login_required, current_user
from app.extensions import db
from app.models.project import Project
from app.models.aufmass import Aufmass
from app.models.position import Position
from app.models.lv import LVPosition
from app.services.license_service import check_user_module_access
modules_bp = Blueprint('modules', __name__)
@modules_bp.route('/<module_name>/formular')
@login_required
def formular(module_name):
if not check_user_module_access(current_user, module_name):
return 'Modul nicht freigeschaltet', 403
try:
mod = __import__(f'app.modules.{module_name}', fromlist=['get_formular_html'])
html = mod.get_formular_html()
aufmass_id = request.args.get('aufmass_id')
if aufmass_id and '<form' in html:
html = html.replace('</form>', f'<input type="hidden" name="aufmass_id" value="{aufmass_id}"></form>', 1)
return html
except (ImportError, AttributeError) as e:
return f'Modul {module_name} nicht gefunden: {e}', 404
@modules_bp.route('/<module_name>/berechnen', methods=['POST'])
@login_required
def berechnen(module_name):
if not check_user_module_access(current_user, module_name):
return jsonify({'error': 'Modul nicht freigeschaltet'}), 403
try:
mod = __import__(f'app.modules.{module_name}', fromlist=['berechne'])
form_data = request.form.to_dict()
aufmass_id = form_data.pop('aufmass_id', None)
sm_nr = form_data.pop('sm_nr', f'{module_name}_auto')
projekt_name = form_data.pop('projekt_name', f'{module_name} Berechnung')
result = mod.berechne(form_data)
# Use existing aufmass if aufmass_id provided
if aufmass_id:
aufmass = Aufmass.query.get(int(aufmass_id))
if not aufmass:
return '<div class="notification is-danger">Aufmaß nicht gefunden.<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'
project = Project.query.get(aufmass.project_id)
if not project or project.company_id != current_user.company_id:
return '<div class="notification is-danger">Kein Zugriff.<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'
locked, holder_id = aufmass.is_locked()
if locked and holder_id != current_user.id:
from app.models.user import User
holder = User.query.get(holder_id)
name = holder.full_name if holder else 'Unbekannt'
return f'<div class="notification is-danger">🔒 {name} bearbeitet dieses Aufmaß gerade.<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'
else:
project = Project.query.filter_by(company_id=current_user.company_id, sm_nr=sm_nr).first()
if not project:
project = Project(
company_id=current_user.company_id,
sm_nr=sm_nr,
bezeichnung=projekt_name,
status='aktiv',
erstellt_von=current_user.id,
)
db.session.add(project)
db.session.flush()
aufmass = Aufmass(project_id=project.id, name='Standard', typ='', sortierung=0, erstellt_von=current_user.id)
db.session.add(aufmass)
db.session.flush()
else:
aufmass = Aufmass.query.filter_by(project_id=project.id).order_by(Aufmass.sortierung).first()
if not aufmass:
aufmass = Aufmass(project_id=project.id, name='Standard', typ='', sortierung=0, erstellt_von=current_user.id)
db.session.add(aufmass)
db.session.flush()
max_sort = db.session.query(db.func.max(Position.sortierung)).filter_by(
aufmass_id=aufmass.id
).scalar() or 0
count = 0
for pos_data in result:
max_sort += 1
explicit_menge = pos_data.get('menge')
pos = Position(
project_id=project.id, aufmass_id=aufmass.id,
pos_nr=pos_data.get('pos_nr', ''),
sortierung=max_sort,
kurztext=pos_data.get('kurztext', ''),
einheit=pos_data.get('einheit', 'ST'),
einzelpreis=float(pos_data.get('einzelpreis', 0)),
menge=float(explicit_menge) if explicit_menge is not None else 0,
faktor=float(pos_data.get('faktor', 1)),
laenge=float(pos_data.get('laenge', 0)),
breite=float(pos_data.get('breite', 0)),
tiefe=float(pos_data.get('tiefe', 0)),
bemerkung=pos_data.get('bemerkung', ''),
gesamtpreis=0,
)
pos.berechne_menge()
if explicit_menge is not None:
pos.menge = float(explicit_menge)
pos.menge_hinten = pos.faktor * pos.menge
pos.gesamtpreis = pos.menge_hinten * pos.einzelpreis
db.session.add(pos)
count += 1
db.session.commit()
return f'''<div class="notification is-success">
<strong>{count} Positionen</strong> berechnet und ins Aufmaß übernommen.
<span class="is-pulled-right tag is-light is-info">Seite wird neu geladen...</span>
</div>
<script>
setTimeout(function() {{
var m = document.getElementById('modul-modal');
if (m) m.classList.remove('is-active');
location.reload();
}}, 1200);
</script>'''
except (ImportError, AttributeError) as e:
return f'<div class="notification is-danger">Modul-Fehler: {e}<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'
except Exception as e:
return f'<div class="notification is-danger">Fehler: {e}<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'