Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb9c655398 | |||
| 4c2657218d |
@@ -38,7 +38,7 @@ def _active_record_query(extra_query=None):
|
||||
return base_query
|
||||
|
||||
|
||||
def add(date_start: str, date_end: str, time_span: list, slots: int, slot_lenght: int, user: str, mail: list=[], note:str="", calendar_enabled: bool=False, title: str=""):
|
||||
def add(date_start: str, date_end: str, time_span: list, slots: int, slot_lenght: int, user: str, mail: list=[], note:str="", calendar_enabled: bool=False, title: str="", custom_fields: list = ()):
|
||||
try:
|
||||
client = MongoClient(cfg.MONGODB_HOST, cfg.MONGODB_PORT)
|
||||
db = _get_tenant_db(client)
|
||||
@@ -54,8 +54,9 @@ def add(date_start: str, date_end: str, time_span: list, slots: int, slot_lenght
|
||||
'mail': mail,
|
||||
'note': note,
|
||||
'title': title,
|
||||
'custom_fields': custom_fields,
|
||||
'calendar_enabled': bool(calendar_enabled),
|
||||
'slots_booked': [], # -> [(start_time, name), ...]the list gets there indexes as the slot 1-defined so is can be counted without an extra variable
|
||||
'slots_booked': [], # -> [(start_time, name,(custom1, custom2,...)), ...]the list gets there indexes as the slot 1-defined so is can be counted without an extra variable
|
||||
'Created': datetime.datetime.now(),
|
||||
'LastUpdated': datetime.datetime.now()
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ def build_client_slot_ics(appointment_id: str, slot_start: str, client_name: str
|
||||
return '\r\n'.join(ics_lines)
|
||||
|
||||
|
||||
def new(date_start: str, date_end: str, time_span: list, slots, slot_length, user: str, mail: list=None, note:str="", calendar_enabled: bool=False, title: str="") -> dict:
|
||||
def new(date_start: str, date_end: str, time_span: list, slots, slot_length, user: str, mail: list=None, note:str="", calendar_enabled: bool=False, title: str="", custom_fields: list = ()) -> dict:
|
||||
"""
|
||||
Generates a link for the executive to send to his clients to book a time Slot
|
||||
"""
|
||||
@@ -215,7 +215,7 @@ def new(date_start: str, date_end: str, time_span: list, slots, slot_length, use
|
||||
normalized_time_span = _normalize_time_span(time_span)
|
||||
normalized_mail = _normalize_mail_list(mail or [])
|
||||
|
||||
id = termin.add(date_start, date_end, normalized_time_span, slots_int, slot_length_int, user, normalized_mail, note, calendar_enabled=calendar_enabled, title=title)
|
||||
id = termin.add(date_start, date_end, normalized_time_span, slots_int, slot_length_int, user, normalized_mail, note, calendar_enabled=calendar_enabled, title=title, custom_fields=custom_fields)
|
||||
id_str = str(id)
|
||||
tenant_id = _current_tenant_id()
|
||||
|
||||
@@ -254,7 +254,7 @@ def new(date_start: str, date_end: str, time_span: list, slots, slot_length, use
|
||||
}
|
||||
|
||||
|
||||
def book_slot(id, date_start_time, name):
|
||||
def book_slot(id, date_start_time, name, custom:list=()):
|
||||
try:
|
||||
item = termin.get_item(id)
|
||||
if not item:
|
||||
@@ -273,7 +273,7 @@ def book_slot(id, date_start_time, name):
|
||||
if existing[0] == date_start_time and existing[1] == name:
|
||||
return False
|
||||
|
||||
slots.append((date_start_time, name))
|
||||
slots.append((date_start_time, name, custom))
|
||||
success = termin.update(id, slots)
|
||||
return bool(success)
|
||||
except Exception as e:
|
||||
@@ -418,6 +418,7 @@ def get_user_upcoming_events(user: str, limit: int = 25) -> list[dict]:
|
||||
'link': link,
|
||||
'calendar_link': calendar_link if item.get('calendar_enabled') else None,
|
||||
'title': str(item.get('title') or ''),
|
||||
'custom_fields': list(item.get('custom_fields')),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -50,6 +50,10 @@ def client(appointment_id):
|
||||
current_user = str(session.get('username', '') or '').strip()
|
||||
appointment_item = termin.get_item(appointment_id) or {}
|
||||
appointment_owner = str(appointment_item.get('user', '') or '').strip()
|
||||
|
||||
# Extract the custom fields defined by the appointment owner
|
||||
custom_fields = appointment_item.get('custom_fields', [])
|
||||
|
||||
can_view_booking_names = False
|
||||
if current_user:
|
||||
try:
|
||||
@@ -72,6 +76,9 @@ def client(appointment_id):
|
||||
if request.method == 'POST':
|
||||
start_daytime = request.form.get('start_day_time')
|
||||
username = request.form.get('client_name')
|
||||
|
||||
custom_answers = request.form.getlist('custom_answers')
|
||||
|
||||
if not start_daytime or not username:
|
||||
flash('Bitte Name und gewünschte Uhrzeit angeben.', 'error')
|
||||
return render_template(
|
||||
@@ -81,9 +88,10 @@ def client(appointment_id):
|
||||
current_user=session.get('username', ''),
|
||||
tenant_id=_current_tenant_id(),
|
||||
can_view_booking_names=can_view_booking_names,
|
||||
custom_fields=custom_fields
|
||||
)
|
||||
|
||||
if appointment_service.book_slot(appointment_id, start_daytime, username):
|
||||
if appointment_service.book_slot(appointment_id, start_daytime, username, custom=custom_answers):
|
||||
return redirect(
|
||||
url_for(
|
||||
'terminplaner.client_success',
|
||||
@@ -103,6 +111,7 @@ def client(appointment_id):
|
||||
current_user=session.get('username', ''),
|
||||
tenant_id=_current_tenant_id(),
|
||||
can_view_booking_names=can_view_booking_names,
|
||||
custom_fields=custom_fields
|
||||
)
|
||||
|
||||
|
||||
@@ -169,13 +178,13 @@ def configure():
|
||||
end = request.form.get('end_date')
|
||||
time = request.form.get('time_frame')
|
||||
slots_amount = request.form.get('slots_amounts')
|
||||
slot_length = request.form.get('slot_length') # Korrigiert: slot_length
|
||||
slot_length = request.form.get('slot_length')
|
||||
mail = request.form.get('mail', '')
|
||||
note = request.form.get('note', '')
|
||||
add_to_calendar = request.form.get('add_to_calendar') == 'on'
|
||||
title = request.form.get('title', '').strip() # Korrigiert: title statt titel
|
||||
title = request.form.get('title', '').strip()
|
||||
custom = request.form.getlist('custom_fields')
|
||||
|
||||
# Abfrage ebenfalls auf title und slot_length angepasst
|
||||
if not start or not end or not time or not slots_amount or not slot_length or not title:
|
||||
flash('Bitte alle Pflichtfelder ausfüllen.', 'error')
|
||||
return render_template(
|
||||
@@ -186,7 +195,7 @@ def configure():
|
||||
)
|
||||
|
||||
# Variablen im Funktionsaufruf aktualisiert
|
||||
result = appointment_service.new(start, end, time, slots_amount, slot_length, session["username"], mail, note, calendar_enabled=add_to_calendar, title=title)
|
||||
result = appointment_service.new(start, end, time, slots_amount, slot_length, session["username"], mail, note, calendar_enabled=add_to_calendar, title=title, custom_fields=custom)
|
||||
flash('Der Terminplan wurde angelegt.', 'success')
|
||||
return render_template(
|
||||
'termin_configure.html',
|
||||
|
||||
@@ -109,6 +109,16 @@
|
||||
<label for="client_name" class="form-label fw-semibold">Ihr Name</label>
|
||||
<input type="text" id="client_name" name="client_name" class="form-control form-control-lg" placeholder="Vor- und Nachname" required>
|
||||
</div>
|
||||
|
||||
{% if custom_fields %}
|
||||
{% for field_label in custom_fields %}
|
||||
<div>
|
||||
<label class="form-label fw-semibold">{{ field_label }}</label>
|
||||
<input type="text" name="custom_answers" class="form-control form-control-lg" placeholder="{{ field_label }} eingeben" required>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex flex-column flex-sm-row gap-2 pt-2">
|
||||
<button type="submit" class="btn btn-primary btn-lg">Termin buchen</button>
|
||||
<a class="btn btn-outline-secondary btn-lg" href="{{ url_for('terminplaner.main', tenant=tenant_id) }}">Zur Übersicht</a>
|
||||
|
||||
@@ -77,6 +77,16 @@
|
||||
<div class="form-text">Wird aus der gebuchten Zeit (abzüglich Pausen) und der Slot-Länge berechnet.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="custom-fields-container" class="mt-4">
|
||||
<h3 class="mb-3">Custom Fields</h3>
|
||||
|
||||
<div class="mb-3 custom-field-row">
|
||||
<input type="text"
|
||||
name="custom_fields"
|
||||
class="form-control form-control-lg custom-dynamic-input"
|
||||
placeholder="Zusatzfeld hinzufügen (z.B. Firma, Kundennummer...)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if mail_service_enabled %}
|
||||
<div>
|
||||
@@ -351,6 +361,39 @@
|
||||
syncTextarea();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const container = document.getElementById('custom-fields-container');
|
||||
|
||||
// Monitor inputs inside the container using event delegation
|
||||
container.addEventListener('input', function (event) {
|
||||
// Only trigger if the user is typing inside our dynamic inputs
|
||||
if (event.target.classList.contains('custom-dynamic-input')) {
|
||||
const allInputs = container.querySelectorAll('.custom-dynamic-input');
|
||||
const lastInput = allInputs[allInputs.length - 1];
|
||||
|
||||
// If the user typed something into the absolute last input field, spawn a new one
|
||||
if (lastInput.value.trim() !== '') {
|
||||
createNewFieldRow(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to generate and append a clean new input row
|
||||
function createNewFieldRow(targetContainer) {
|
||||
const rowDiv = document.createElement('div');
|
||||
rowDiv.className = 'mb-3 custom-field-row';
|
||||
|
||||
rowDiv.innerHTML = `
|
||||
<input type="text"
|
||||
name="custom_fields"
|
||||
class="form-control form-control-lg custom-dynamic-input"
|
||||
placeholder="Nächstes Zusatzfeld...">
|
||||
`;
|
||||
|
||||
targetContainer.appendChild(rowDiv);
|
||||
}
|
||||
});
|
||||
|
||||
// Event Listeners Registration
|
||||
buildButton.addEventListener('click', renderRows);
|
||||
startDateInput.addEventListener('change', renderRows);
|
||||
|
||||
Reference in New Issue
Block a user