Initial commit – AufmaßCreater v2.35
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
|
||||
from flask_login import login_required, current_user
|
||||
from app.extensions import db
|
||||
from app.models.custom_module import CustomModule, CustomModuleAssignment
|
||||
from app.models.project import Project
|
||||
from app.models.aufmass import Aufmass
|
||||
from app.models.position import Position
|
||||
from app.models.user import User
|
||||
from app.models.company import Company
|
||||
from app.services.custom_module_renderer import render_form
|
||||
from app.services.custom_module_executor import execute_rules
|
||||
import json
|
||||
|
||||
custom_modules_bp = Blueprint('custom_modules', __name__, url_prefix='/custom-modules')
|
||||
|
||||
def _can_manage(user, module=None):
|
||||
if user.is_superadmin():
|
||||
return True
|
||||
if user.is_firmadmin():
|
||||
if module is None:
|
||||
return True
|
||||
if module.is_template:
|
||||
return False
|
||||
return module.company_id == user.company_id
|
||||
return False
|
||||
|
||||
def _can_use(user, module):
|
||||
if user.is_superadmin():
|
||||
return True
|
||||
if user.is_firmadmin() and module.company_id == user.company_id:
|
||||
return True
|
||||
if not module.is_active:
|
||||
return False
|
||||
return CustomModuleAssignment.query.filter_by(
|
||||
module_id=module.id, user_id=user.id
|
||||
).first() is not None
|
||||
|
||||
@custom_modules_bp.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
if not _can_manage(current_user):
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
|
||||
if current_user.is_superadmin():
|
||||
templates = CustomModule.query.filter_by(is_template=True).order_by(CustomModule.sort_index).all()
|
||||
company_modules = CustomModule.query.filter_by(is_template=False).order_by(CustomModule.company_id, CustomModule.sort_index).all()
|
||||
companies = Company.query.order_by(Company.name).all()
|
||||
else:
|
||||
templates = CustomModule.query.filter_by(is_template=True, is_active=True).order_by(CustomModule.sort_index).all()
|
||||
company_modules = CustomModule.query.filter_by(
|
||||
company_id=current_user.company_id, is_template=False
|
||||
).order_by(CustomModule.sort_index).all()
|
||||
companies = []
|
||||
|
||||
return render_template('custom_modules/index.html',
|
||||
templates=templates,
|
||||
company_modules=company_modules,
|
||||
companies=companies)
|
||||
|
||||
@custom_modules_bp.route('/neu', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def neu():
|
||||
if not _can_manage(current_user):
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name', '').strip()
|
||||
if not name:
|
||||
flash('Name ist erforderlich.', 'danger')
|
||||
return render_template('custom_modules/edit.html', module=None)
|
||||
|
||||
module = CustomModule(
|
||||
company_id=current_user.company_id if not current_user.is_superadmin() else None,
|
||||
name=name,
|
||||
description=request.form.get('description', ''),
|
||||
kategorie=request.form.get('kategorie', 'allgemein'),
|
||||
icon=request.form.get('icon', '🔧'),
|
||||
is_template=bool(request.form.get('is_template')) if current_user.is_superadmin() else False,
|
||||
form_json='[]',
|
||||
rules_json='[]',
|
||||
created_by=current_user.id,
|
||||
)
|
||||
db.session.add(module)
|
||||
db.session.commit()
|
||||
flash(f'Modul "{name}" erstellt.', 'success')
|
||||
return redirect(url_for('custom_modules.edit', module_id=module.id))
|
||||
|
||||
return render_template('custom_modules/edit.html', module=None,
|
||||
is_superadmin=current_user.is_superadmin())
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/bearbeiten', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
|
||||
if request.method == 'POST':
|
||||
module.name = request.form.get('name', module.name).strip()
|
||||
module.description = request.form.get('description', '')
|
||||
module.kategorie = request.form.get('kategorie', 'allgemein')
|
||||
module.icon = request.form.get('icon', '🔧')
|
||||
module.is_active = bool(request.form.get('is_active', True))
|
||||
if current_user.is_superadmin():
|
||||
module.is_template = bool(request.form.get('is_template', module.is_template))
|
||||
db.session.commit()
|
||||
flash('Modul aktualisiert.', 'success')
|
||||
return redirect(url_for('custom_modules.index'))
|
||||
|
||||
users = []
|
||||
if module.company_id:
|
||||
users = User.query.filter_by(company_id=module.company_id, aktiv=True).order_by(User.vorname).all()
|
||||
assignments = {a.user_id: a for a in module.assignments}
|
||||
|
||||
return render_template('custom_modules/edit.html', module=module,
|
||||
users=users, assignments=assignments,
|
||||
is_superadmin=current_user.is_superadmin())
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/builder')
|
||||
@login_required
|
||||
def builder(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
return render_template('custom_modules/builder.html', module=module)
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/loeschen', methods=['POST'])
|
||||
@login_required
|
||||
def loeschen(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
|
||||
name = module.name
|
||||
db.session.delete(module)
|
||||
db.session.commit()
|
||||
flash(f'Modul "{name}" gelöscht.', 'success')
|
||||
return redirect(url_for('custom_modules.index'))
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/importieren', methods=['POST'])
|
||||
@login_required
|
||||
def importieren(module_id):
|
||||
template = CustomModule.query.get_or_404(module_id)
|
||||
if not template.is_template:
|
||||
flash('Nur Vorlagen können importiert werden.', 'danger')
|
||||
return redirect(url_for('custom_modules.index'))
|
||||
if not current_user.is_firmadmin():
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('custom_modules.index'))
|
||||
|
||||
existing = CustomModule.query.filter_by(
|
||||
company_id=current_user.company_id,
|
||||
original_template_id=template.id
|
||||
).first()
|
||||
if existing:
|
||||
flash(f'Vorlage "{template.name}" bereits als "{existing.name}" importiert.', 'warning')
|
||||
return redirect(url_for('custom_modules.index'))
|
||||
|
||||
copy = CustomModule(
|
||||
company_id=current_user.company_id,
|
||||
original_template_id=template.id,
|
||||
name=template.name,
|
||||
description=template.description,
|
||||
kategorie=template.kategorie,
|
||||
icon=template.icon,
|
||||
form_json=template.form_json,
|
||||
rules_json=template.rules_json,
|
||||
is_template=False,
|
||||
created_by=current_user.id,
|
||||
)
|
||||
db.session.add(copy)
|
||||
db.session.commit()
|
||||
flash(f'Vorlage "{template.name}" importiert – jetzt kannst du sie anpassen.', 'success')
|
||||
return redirect(url_for('custom_modules.edit', module_id=copy.id))
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/als-vorlage', methods=['POST'])
|
||||
@login_required
|
||||
def als_vorlage(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not current_user.is_superadmin():
|
||||
flash('Keine Berechtigung.', 'danger')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
|
||||
template = CustomModule(
|
||||
company_id=None,
|
||||
original_template_id=None,
|
||||
name=module.name,
|
||||
description=module.description,
|
||||
kategorie=module.kategorie,
|
||||
icon=module.icon,
|
||||
form_json=module.form_json,
|
||||
rules_json=module.rules_json,
|
||||
is_template=True,
|
||||
created_by=current_user.id,
|
||||
)
|
||||
db.session.add(template)
|
||||
db.session.commit()
|
||||
flash(f'Modul "{module.name}" als globale Vorlage gespeichert.', 'success')
|
||||
return redirect(url_for('custom_modules.index'))
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/user/<int:user_id>/toggle', methods=['POST'])
|
||||
@login_required
|
||||
def user_toggle(module_id, user_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
return jsonify({'error': 'Keine Berechtigung'}), 403
|
||||
|
||||
user = User.query.get_or_404(user_id)
|
||||
assignment = CustomModuleAssignment.query.filter_by(
|
||||
module_id=module.id, user_id=user.id
|
||||
).first()
|
||||
|
||||
data = request.get_json(silent=True) or {}
|
||||
active = data.get('active', False)
|
||||
can_edit = data.get('can_edit', False)
|
||||
|
||||
if active:
|
||||
if not assignment:
|
||||
assignment = CustomModuleAssignment(
|
||||
module_id=module.id, user_id=user.id, can_edit=can_edit
|
||||
)
|
||||
db.session.add(assignment)
|
||||
db.session.commit()
|
||||
return jsonify({'message': f'{user.full_name} hat jetzt Zugriff.', 'active': True})
|
||||
return jsonify({'active': True})
|
||||
else:
|
||||
if assignment:
|
||||
db.session.delete(assignment)
|
||||
db.session.commit()
|
||||
return jsonify({'message': f'Zugriff für {user.full_name} entzogen.', 'active': False})
|
||||
return jsonify({'active': False})
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/api/form-json', methods=['GET', 'PUT'])
|
||||
@login_required
|
||||
def api_form_json(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
return jsonify({'error': 'Keine Berechtigung'}), 403
|
||||
|
||||
if request.method == 'PUT':
|
||||
try:
|
||||
data = request.get_json(force=True)
|
||||
module.form_json = json.dumps(data, ensure_ascii=False)
|
||||
db.session.commit()
|
||||
return jsonify({'ok': True})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 400
|
||||
|
||||
return jsonify(json.loads(module.form_json or '[]'))
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/api/rules-json', methods=['GET', 'PUT'])
|
||||
@login_required
|
||||
def api_rules_json(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
return jsonify({'error': 'Keine Berechtigung'}), 403
|
||||
|
||||
if request.method == 'PUT':
|
||||
try:
|
||||
data = request.get_json(force=True)
|
||||
module.rules_json = json.dumps(data, ensure_ascii=False)
|
||||
db.session.commit()
|
||||
return jsonify({'ok': True})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 400
|
||||
|
||||
return jsonify(json.loads(module.rules_json or '[]'))
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/api/preview')
|
||||
@login_required
|
||||
def api_preview(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
return '<div class="notification is-danger">Keine Berechtigung.</div>'
|
||||
html = render_form(module.form_json, module_id)
|
||||
return html
|
||||
|
||||
@custom_modules_bp.route('/api/available')
|
||||
@login_required
|
||||
def api_available():
|
||||
modules = CustomModule.query.filter(
|
||||
CustomModule.is_active == True,
|
||||
CustomModule.is_template == False,
|
||||
CustomModule.company_id == current_user.company_id
|
||||
).order_by(CustomModule.sort_index).all()
|
||||
|
||||
result = []
|
||||
for m in modules:
|
||||
if current_user.is_firmadmin() or current_user.is_superadmin():
|
||||
result.append({'id': m.id, 'name': m.name, 'icon': m.icon, 'kategorie': m.kategorie})
|
||||
elif _can_use(current_user, m):
|
||||
result.append({'id': m.id, 'name': m.name, 'icon': m.icon, 'kategorie': m.kategorie})
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/formular')
|
||||
@login_required
|
||||
def formular(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_use(current_user, module):
|
||||
return '<div class="notification is-danger">Keine Berechtigung für dieses Modul.</div>'
|
||||
|
||||
aufmass_id = request.args.get('aufmass_id')
|
||||
html = render_form(module.form_json, module_id, aufmass_id=aufmass_id)
|
||||
return html
|
||||
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/berechnen', methods=['POST'])
|
||||
@login_required
|
||||
def berechnen(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_use(current_user, module):
|
||||
return '<div class="notification is-danger">Keine Berechtigung.</div>'
|
||||
|
||||
aufmass_id = request.args.get('aufmass_id')
|
||||
if not aufmass_id:
|
||||
return '<div class="notification is-danger">Kein Aufmaß ausgewählt.<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'
|
||||
|
||||
aufmass = Aufmass.query.get_or_404(aufmass_id)
|
||||
project = Project.query.get(aufmass.project_id)
|
||||
if not project:
|
||||
return '<div class="notification is-danger">Projekt nicht gefunden.<br><button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button></div>'
|
||||
project_id = project.id
|
||||
company_id = project.company_id
|
||||
|
||||
form_data = {k: v for k, v in request.form.items()}
|
||||
|
||||
rules = json.loads(module.rules_json) if isinstance(module.rules_json, str) else module.rules_json
|
||||
positions_data = execute_rules(form_data, module.rules_json, company_id)
|
||||
|
||||
if not positions_data:
|
||||
return '''
|
||||
<div class="notification is-warning" style="margin-top:10px">
|
||||
Keine Bedingungen erfüllt – es wurden keine Positionen erzeugt.
|
||||
<button class="delete" onclick="closeModulModal()"></button>
|
||||
</div>
|
||||
<button class="button is-small is-light mt-2" onclick="closeModulModal()">Schließen</button>'''
|
||||
|
||||
created = 0
|
||||
for pd in positions_data:
|
||||
pos = Position(
|
||||
aufmass_id=aufmass.id,
|
||||
project_id=project_id,
|
||||
pos_nr=pd.get('pos_nr', ''),
|
||||
kurztext=pd.get('kurztext', ''),
|
||||
langtext=pd.get('langtext', ''),
|
||||
einheit=pd.get('einheit', 'ST'),
|
||||
menge=pd.get('menge', 0),
|
||||
faktor=pd.get('faktor', 1),
|
||||
laenge=pd.get('laenge', 0),
|
||||
breite=pd.get('breite', 0),
|
||||
tiefe=pd.get('tiefe', 0),
|
||||
einzelpreis=pd.get('einzelpreis', 0),
|
||||
bemerkung=pd.get('bemerkung', ''),
|
||||
sort_index=pd.get('sort_index', 0),
|
||||
)
|
||||
db.session.add(pos)
|
||||
created += 1
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return f'''<div class="notification is-success">
|
||||
<strong>{created} Positionen</strong> 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>'''
|
||||
|
||||
|
||||
@custom_modules_bp.route('/api/sort-batch', methods=['POST'])
|
||||
@login_required
|
||||
def sort_batch():
|
||||
if not _can_manage(current_user):
|
||||
return jsonify({'error': 'Keine Berechtigung'}), 403
|
||||
|
||||
data = request.get_json(force=True)
|
||||
if not isinstance(data, list):
|
||||
return jsonify({'error': 'Erwarte Liste von {id, sort_index}'}), 400
|
||||
|
||||
for item in data:
|
||||
module = CustomModule.query.get(item.get('id'))
|
||||
if not module:
|
||||
continue
|
||||
if not _can_manage(current_user, module):
|
||||
continue
|
||||
module.sort_index = item.get('sort_index', 0)
|
||||
|
||||
db.session.commit()
|
||||
return jsonify({'ok': True, 'updated': len(data)})
|
||||
|
||||
|
||||
@custom_modules_bp.route('/<int:module_id>/sort', methods=['POST'])
|
||||
@login_required
|
||||
def sort(module_id):
|
||||
module = CustomModule.query.get_or_404(module_id)
|
||||
if not _can_manage(current_user, module):
|
||||
return jsonify({'error': 'Keine Berechtigung'}), 403
|
||||
|
||||
data = request.get_json(force=True)
|
||||
sort_index = data.get('sort_index', 0)
|
||||
module.sort_index = sort_index
|
||||
db.session.commit()
|
||||
return jsonify({'ok': True})
|
||||
Reference in New Issue
Block a user