feat(events): Add billing info and organizer name
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"""add billing info and organizer name to event
|
||||
|
||||
Revision ID: 914ebe23f071
|
||||
Revises: 13084c5c1f68
|
||||
Create Date: 2025-12-12 12:26:13.314293
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "914ebe23f071"
|
||||
down_revision: Union[str, Sequence[str], None] = "13084c5c1f68"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column(
|
||||
"event",
|
||||
sa.Column(
|
||||
"billed", sa.Boolean(), nullable=False, server_default=sa.text("false")
|
||||
),
|
||||
)
|
||||
op.add_column(
|
||||
"event",
|
||||
sa.Column(
|
||||
"exclude_from_billing",
|
||||
sa.Boolean(),
|
||||
nullable=False,
|
||||
server_default=sa.text("false"),
|
||||
),
|
||||
)
|
||||
op.add_column("event", sa.Column("organizer_name", sa.String(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("event", "organizer_name")
|
||||
op.drop_column("event", "exclude_from_billing")
|
||||
op.drop_column("event", "billed")
|
||||
# ### end Alembic commands ###
|
||||
@@ -241,6 +241,8 @@ async def edit_event(
|
||||
event.description = form_data.get("eventDescription")
|
||||
event.recipe_link = form_data.get("recipeLink")
|
||||
event.ignore_subscriptions = form_data.get("ignoreSubscriptions") == "on"
|
||||
event.organizer_name = form_data.get("organizerName")
|
||||
event.exclude_from_billing = form_data.get("excludeFromBilling") == "on"
|
||||
|
||||
session.commit()
|
||||
|
||||
@@ -260,6 +262,8 @@ async def add_event(request: Request, session: SessionDep, user: StrictUserDep):
|
||||
description=form_data.get("eventDescription"),
|
||||
recipe_link=form_data.get("recipeLink"),
|
||||
ignore_subscriptions=form_data.get("ignoreSubscriptions") == "on",
|
||||
organizer_name=form_data.get("organizerName"),
|
||||
exclude_from_billing=form_data.get("excludeFromBilling") == "on",
|
||||
)
|
||||
session.add(event)
|
||||
session.commit()
|
||||
@@ -448,8 +452,11 @@ def sync_with_grist_route(event_id: int, session: SessionDep, user: StrictUserDe
|
||||
event = session.scalars(statement).one()
|
||||
|
||||
entries_written = sync_with_grist(event)
|
||||
|
||||
message = "Es wurden keine Einträge geschrieben."
|
||||
if entries_written > 0:
|
||||
event.billed = True
|
||||
session.commit()
|
||||
message = f"Erfolgreich {entries_written} Einträge geschrieben."
|
||||
return RedirectResponse(
|
||||
url=f"/event/{event_id}?message={quote_plus(message)}",
|
||||
|
||||
@@ -36,6 +36,11 @@ class Event(Base):
|
||||
subscriptions_applied: Mapped[bool] = mapped_column(default=False, nullable=False)
|
||||
ignore_subscriptions: Mapped[bool] = mapped_column(default=False, nullable=False)
|
||||
|
||||
billed: Mapped[bool] = mapped_column(default=False, nullable=False)
|
||||
exclude_from_billing: Mapped[bool] = mapped_column(default=False, nullable=False)
|
||||
|
||||
organizer_name: Mapped[str] = mapped_column(nullable=True)
|
||||
|
||||
registrations: Mapped[list["Registration"]] = relationship(
|
||||
"Registration", cascade="all, delete"
|
||||
)
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
<small class="form-text text-muted">Leer lassen für Sonntag Abend vor dem Event</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="organizerName" class="form-label">Organisator*in</label>
|
||||
<input type="text" class="form-control" id="organizerName" name="organizerName" {% if edit_mode %}value="{{ event.organizer_name }}"{% endif %}>
|
||||
<small class="form-text text-muted">Name der Person, die das Event organisiert.</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="recipeLink" class="form-label">Rezept-Link</label>
|
||||
<input type="text" class="form-control" id="recipeLink" name="recipeLink" {% if edit_mode %}value="{{ event.recipe_link }}"{% endif %}>
|
||||
@@ -34,11 +40,18 @@
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="ignoreSubscriptions" name="ignoreSubscriptions" {% if (edit_mode and event.ignore_subscriptions) or not edit_mode %}checked{% endif %}>
|
||||
<label class="form-check-label" for="ignoreSubscriptions">Dauerhafte Anmeldung ignorieren</label>
|
||||
<small class="form-text text-muted">
|
||||
Aktivieren, um dauerhafte Anmeldungen für dieses Event zu ignorieren. Das sollte für alle Events getan werden, die keine offiziellen AG Kochen Kochabende sind.
|
||||
</small>
|
||||
<small class="form-text text-muted">
|
||||
Aktivieren, um dauerhafte Anmeldungen für dieses Event zu ignorieren. Das sollte für alle Events getan werden, die keine offiziellen AG Kochen Kochabende sind.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="excludeFromBilling" name="excludeFromBilling" {% if edit_mode and event.exclude_from_billing %}checked{% endif %}>
|
||||
<label class="form-check-label" for="excludeFromBilling">Keine Abrechnung</label>
|
||||
<small class="form-text text-muted">
|
||||
Aktivieren, um dieses Event von der Abrechnung auszuschließen.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Event {% if edit_mode %}bearbeiten{% else %}erstellen{% endif %}</button>
|
||||
</form>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
{% block content %}
|
||||
<p class="h1">{{ event.title }}</p>
|
||||
<p class="text-muted">{{ event.event_time.strftime('%A, %d.%m.%Y') }}</p>
|
||||
{% if event.organizer_name %}<p>Organisiert von {{ event.organizer_name }}</p>{% endif %}
|
||||
<p>{{ event.description }}</p>
|
||||
<hr class="hr"/>
|
||||
{% if message %}
|
||||
@@ -59,7 +60,7 @@
|
||||
</div>
|
||||
<div class="col-6 p-1">
|
||||
{% if user -%}
|
||||
<a href="/event/{{event.id}}/edit" class="btn btn-secondary w-100" target="_blank">
|
||||
<a href="/event/{{event.id}}/edit" class="btn btn-secondary w-100">
|
||||
<i class="bi bi-pen m-2"></i> Event bearbeiten
|
||||
</a>
|
||||
{% else -%}
|
||||
@@ -77,7 +78,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-6 p-1">
|
||||
<a href="/event/{{event.id}}/sync_with_grist" class="btn btn-secondary w-100">
|
||||
<a href="/event/{{event.id}}/sync_with_grist" class="btn btn-secondary w-100 {% if event.exclude_from_billing %}disabled{% endif %}">
|
||||
<i class="bi bi-cash-coin m-2"></i> Abrechnen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -33,18 +33,25 @@
|
||||
|
||||
|
||||
{% for event in events %}
|
||||
<div class="col">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-1">{{ event.title }}</h5>
|
||||
<p class="text-muted mb-3"><i class="bi bi-calendar"></i> {{ event.event_time.strftime('%A, %d.%m.%Y')
|
||||
}}
|
||||
</p>
|
||||
<p class="card-text">{{ event.description }}</p>
|
||||
<a href="event/{{ event.id }}" class="btn btn-sm {% if event.registration_deadline > now %}btn-primary{% else %}btn-secondary{% endif %}">{% if event.registration_deadline > now %}Zur Anmeldung{% else %}Details ansehen{% endif %}</a>
|
||||
<div class="col">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<div>
|
||||
<h5 class="card-title mb-0">
|
||||
{{ event.title }}
|
||||
{% if event.billed %}<i class="bi bi-cash-coin" title="Abgerechnet"></i>{% endif %}
|
||||
{% if event.exclude_from_billing %}<i class="bi bi-ban" title="Keine Abrechung"></i>{% endif %}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
{% if event.organizer_name %}<p class="text-muted small mb-0"><i class="bi bi-person"></i> {{ event.organizer_name }}</p>{% endif %}
|
||||
</div>
|
||||
<p class="text-muted mb-3"><i class="bi bi-calendar"></i> {{ event.event_time.strftime('%A, %d.%m.%Y') }}</p>
|
||||
<p class="card-text">{{ event.description }}</p>
|
||||
<a href="event/{{ event.id }}" class="btn btn-sm {% if event.registration_deadline > now %}btn-primary{% else %}btn-secondary{% endif %}">{% if event.registration_deadline > now %}Zur Anmeldung{% else %}Details ansehen{% endif %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user