Browse Source

add ausbildung

main
Christoph Marzell 1 month ago
parent
commit
72f084062a
  1. 7
      Dockerfile
  2. 7
      app/controllers/entries_controller.rb
  3. 4
      app/controllers/static_pages_controller.rb
  4. 10
      app/models/entry.rb
  5. 34
      app/views/entries/_form.html.erb
  6. 14
      app/views/entries/index.html.erb
  7. 33
      app/views/layouts/application.html.erb
  8. 43
      app/views/static_pages/impressum.html.erb
  9. 31
      bin/docker-entrypoint
  10. 6
      config/routes.rb
  11. 5
      db/migrate/20251109044107_add_beschreibung_to_entries.rb
  12. 5
      db/migrate/20251109044216_add_kosten_to_entries.rb
  13. 4
      db/schema.rb

7
Dockerfile

@ -62,6 +62,9 @@ USER rails:rails
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost:3000 || exit 1
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]
#EXPOSE 3000
#CMD ["./bin/rails", "server"]

7
app/controllers/entries_controller.rb

@ -36,6 +36,9 @@ class EntriesController < ApplicationController
entries.sum(&:kilometer_pauschale)
end
@fortbildungskosten_by_year = Entry.total_fortbildungskosten_by_year(current_user)
# Voraussichtliches Ende je Kombination basierend auf weekly_target_matrix
@estimated_end_by_typ_art = {}
@remaining_minutes_matrix.each do |typ, arts|
@ -106,7 +109,9 @@ class EntriesController < ApplicationController
:minutes,
:praktikums_typ,
:entry_art,
:distance_km
:distance_km,
:beschreibung,
:kosten
)
end

4
app/controllers/static_pages_controller.rb

@ -0,0 +1,4 @@
class StaticPagesController < ApplicationController
def impressum
end
end

10
app/models/entry.rb

@ -12,7 +12,7 @@ class Entry < ApplicationRecord
before_save :normalize_time
PRAKTIKUMSTYPEN = %w[propädeutikum fachspezifikum]
ENTRY_ARTEN = %w[Praktikum Selbsterfahrung Supervision]
ENTRY_ARTEN = %w[Praktikum Selbsterfahrung Supervision Fortbildung]
validates :praktikums_typ, inclusion: { in: PRAKTIKUMSTYPEN }
validates :entry_art, inclusion: { in: ENTRY_ARTEN }
@ -23,6 +23,12 @@ class Entry < ApplicationRecord
distance_km * 0.42
end
def self.total_fortbildungskosten_by_year(user)
where(user: user, entry_art: 'Fortbildung')
.group_by { |e| e.date.year }
.transform_values { |entries| entries.sum { |e| e.kosten.to_f } }
end
def jahr
date.year
end
@ -42,6 +48,8 @@ class Entry < ApplicationRecord
entry.praktikums_typ,
entry.entry_art,
entry.distance_km,
entry.beschreibung,
entry.kosten,
entry.user.email
]
end

34
app/views/entries/_form.html.erb

@ -11,7 +11,7 @@
<% end %>
<!-- Erste Zeile: Datum, Stunden, Minuten -->
<div class="row g-3">
<div class="row g-3 mt-1">
<div class="col-12 col-md-4">
<%= form.label :date, 'Datum', class: 'form-label' %>
<%= form.text_field :date,
@ -46,7 +46,7 @@
<div class="col-12">
<%= form.label :entry_art, 'Art', class: 'form-label' %>
<%= form.select :entry_art, Entry::ENTRY_ARTEN, {}, class: 'form-select' %>
<%= form.select :entry_art, Entry::ENTRY_ARTEN, {}, class: 'form-select', id: 'entry_art_select' %>
</div>
<div class="col-12">
@ -56,6 +56,20 @@
min: 0,
value: form.object.distance_km || 0 %>
</div>
<div id="fortbildung-fields" style="<%= form.object.entry_art == "Fortbildung" ? '' : 'display: none;' %>">
<div class="col-12 col-md-4">
<%= form.label :beschreibung, 'Beschreibung', class: 'form-label' %>
<%= form.text_field :beschreibung, class: 'form-control' %>
</div>
<div class="col-12 col-md-4">
<%= form.label :kosten, 'Kosten (z. B. Teilnahmegebühr)', class: 'form-label' %>
<%= form.number_field :kosten, class: 'form-control', min: 0, step: 0.01 %>
</div>
</div>
</div>
<!-- Buttons -->
@ -64,3 +78,19 @@
<%= link_to 'Zurück', entries_path, class: 'btn btn-secondary ms-2' %>
</div>
<% end %>
<script>
document.addEventListener("DOMContentLoaded", function () {
const entryArtSelect = document.getElementById("entry_art_select");
const fortbildungFields = document.getElementById("fortbildung-fields");
if (entryArtSelect && fortbildungFields) {
entryArtSelect.addEventListener("change", function () {
if (entryArtSelect.value === "Fortbildung") {
fortbildungFields.style.display = "block";
} else {
fortbildungFields.style.display = "none";
}
});
}
});
</script>

14
app/views/entries/index.html.erb

@ -13,6 +13,12 @@
</p>
<% end %>
<h5>💶 Fortbildungskosten</h5>
<% @fortbildungskosten_by_year.each do |year, sum| %>
<p><strong><%= year %>:</strong> <%= number_to_currency(sum, unit: "€", separator: ",", delimiter: ".", precision: 2) %></p>
<% end %>
<p><strong>Gesamtzeit:</strong> <%= @total_minutes / 60 %> h <%= @total_minutes % 60 %> min</p>
</div>
@ -84,8 +90,12 @@
<tr>
<td><%= entry.date.strftime('%d.%m.%Y') %></td>
<td><%= entry.hours.to_i %>h <%= entry.minutes.to_i %>min</td>
<td><%= entry.praktikums_typ.capitalize %></td>
<td><%= entry.entry_art.capitalize %></td>
<td>
<%= entry.entry_art == "Fortbildung" ? "Fortbildung" : entry.praktikums_typ.capitalize %>
</td>
<td>
<%= entry.entry_art == "Fortbildung" ? entry.beschreibung : entry.entry_art.capitalize %>
</td>
<td><%= entry.distance_km.to_f %> km</td>
<td><%= number_to_currency(entry.kilometer_pauschale, unit: "€", separator: ",", delimiter: ".") %></td>
<td class="text-end">

33
app/views/layouts/application.html.erb

@ -11,11 +11,36 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/themes/material_blue.css">
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" defer></script>
<!-- Flatpickr JS -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<!-- JS: Flatpickr Init -->
<script defer>
document.addEventListener("DOMContentLoaded", function () {
flatpickr(".flatpickr", {
dateFormat: "d.m.Y",
allowInput: true
});
});
</script>
<%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
</head>
<body>
<script defer>
document.addEventListener("DOMContentLoaded", function () {
flatpickr(".flatpickr", {
dateFormat: "d.m.Y",
allowInput: true
});
});
</script>
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4">
<div class="container">
<%= link_to "Praktikumsuhr", root_path, class: "navbar-brand" %>
@ -59,5 +84,11 @@
<%= yield %>
</div>
<footer class="text-center mt-5">
<%= link_to "Impressum & Datenschutz", impressum_path, class: "text-muted" %>
</footer>
</body>
</html>

43
app/views/static_pages/impressum.html.erb

@ -0,0 +1,43 @@
<h1>Impressum</h1>
<p><strong>Angaben gemäß § 5 E-Commerce-Gesetz (ECG), § 24 Mediengesetz und § 14 UGB:</strong></p>
<p>
<p>
Christoph Marzell<br>
Maierhof 20 <br>
2564 Furth an der Triesting<br>
E-Mail: christoph@marzell.net
</p>
<hr>
<h2>Datenschutzerklärung</h2>
<p>
Diese Website speichert personenbezogene Daten nur im technisch notwendigen Umfang. Alle gespeicherten Daten werden nicht verkauft oder weitergegeben.
</p>
<h3>Erhobene Daten</h3>
<ul>
<li>Registrierte E-Mail-Adresse zur Anmeldung</li>
<li>Eingetragene Stunden & Zeiten</li>
<li>Optional: Kilometerdaten für Fahrtkosten</li>
</ul>
<h3>Speicherung</h3>
<p>
Die Daten werden auf dem Server gespeichert, der sich in Deutschland befindet. Es werden keine Daten an Dritte weitergegeben.
</p>
<h3>Cookies</h3>
<p>
Diese Webanwendung verwendet technisch notwendige Cookies für Login und Sitzungssteuerung.
</p>
<h3>Kontakt</h3>
<p>
Bei Fragen zur Datenverarbeitung: christoph@marzell.net
</p>
<hr>
<p><small>Diese Seite wurde automatisch generiert. Es besteht kein Anspruch auf rechtliche Vollständigkeit.</small></p>

31
bin/docker-entrypoint

@ -1,8 +1,27 @@
#!/bin/bash -e
#!/bin/sh
# If running the rails server then create or migrate existing database
if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then
./bin/rails db:prepare
fi
set -e
exec "${@}"
bundle config set without 'development test'
bundle check || bundle install
cd ..
echo ===========================================
echo ${RAILS_ENV}
echo ===========================================
echo Create Database
echo ${RAILS_ENV}
echo ===========================================
bundle exec rails db:create RAILS_ENV=${RAILS_ENV} || true
echo ===========================================
echo ${RAILS_ENV}
echo ===========================================
bundle exec rails db:migrate RAILS_ENV=${RAILS_ENV} || true
echo ===========================================
echo ${RAILS_ENV}
echo ===========================================
bundle exec rails db:seed RAILS_ENV=${RAILS_ENV} || true
echo ===========================================
echo ${PORT}
echo ===========================================
bundle exec puma -C config/puma.rb

6
config/routes.rb

@ -15,8 +15,10 @@ Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'users/registrations'
}
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
get '/impressum', to: 'static_pages#impressum'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
# Can be used by load balancers and uptime monitors to verify that the app is live.

5
db/migrate/20251109044107_add_beschreibung_to_entries.rb

@ -0,0 +1,5 @@
class AddBeschreibungToEntries < ActiveRecord::Migration[7.1]
def change
add_column :entries, :beschreibung, :string
end
end

5
db/migrate/20251109044216_add_kosten_to_entries.rb

@ -0,0 +1,5 @@
class AddKostenToEntries < ActiveRecord::Migration[7.1]
def change
add_column :entries, :kosten, :decimal
end
end

4
db/schema.rb

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2025_11_08_073233) do
ActiveRecord::Schema[7.1].define(version: 2025_11_09_044216) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -24,6 +24,8 @@ ActiveRecord::Schema[7.1].define(version: 2025_11_08_073233) do
t.string "praktikums_typ", default: "propädeutikum", null: false
t.string "entry_art", default: "Praktikum", null: false
t.integer "distance_km", default: 0, null: false
t.string "beschreibung"
t.decimal "kosten"
t.index ["user_id"], name: "index_entries_on_user_id"
end

Loading…
Cancel
Save