From 33eaec44e01e1aa6375cb0653fdcf4062bd34a28 Mon Sep 17 00:00:00 2001 From: Christoph Marzell Date: Sun, 9 Nov 2025 10:33:09 +0100 Subject: [PATCH] sort by year --- app/models/entry.rb | 205 +++++++++++++++++++++++++------------------- 1 file changed, 119 insertions(+), 86 deletions(-) diff --git a/app/models/entry.rb b/app/models/entry.rb index 531f54a..7c709c7 100644 --- a/app/models/entry.rb +++ b/app/models/entry.rb @@ -1,88 +1,121 @@ class Entry < ApplicationRecord - - require 'csv' - - - belongs_to :user - - validates :date, :hours, :minutes, presence: true - validates :hours, numericality: { only_integer: true, greater_than_or_equal_to: 0 } - validates :minutes, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than: 60 } - - before_save :normalize_time - - PRAKTIKUMSTYPEN = %w[propädeutikum fachspezifikum] - ENTRY_ARTEN = %w[Praktikum Selbsterfahrung Supervision Fortbildung Semesterkosten] - - validates :praktikums_typ, inclusion: { in: PRAKTIKUMSTYPEN } - validates :entry_art, inclusion: { in: ENTRY_ARTEN } - validates :distance_km, numericality: { only_integer: true, greater_than_or_equal_to: 0 } - - after_initialize :set_default_date, if: :new_record? - - def set_default_date - self.date ||= Date.today - end - - def kilometer_pauschale - return 0 unless distance_km.present? - 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 self.total_selbsterfahrungskosten_by_year(user) - where(user: user, entry_art: 'Selbsterfahrung') - .group_by { |e| e.date.year } - .transform_values { |entries| entries.sum { |e| e.kosten.to_f } } - end - - def self.total_supervision_by_year(user) - where(user: user, entry_art: 'Supervision') - .group_by { |e| e.date.year } - .transform_values { |entries| entries.sum { |e| e.kosten.to_f } } - end - - def self.total_semesterkosten_by_year(user) - where(user: user) - .group_by { |e| e.date.year } - .transform_values { |entries| entries.sum { |e| e.kosten.to_f } } - end - - def jahr - date.year - end - - def total_minutes - hours * 60 + minutes - end - def self.to_csv - CSV.generate(headers: true, col_sep: ";") do |csv| - csv << %w[Datum Stunden Minuten Typ Art Kilometer User] - - all.each do |entry| - csv << [ - entry.date, - entry.hours, - entry.minutes, - entry.praktikums_typ, - entry.entry_art, - entry.distance_km, - entry.beschreibung, - entry.kosten, - entry.user.email - ] - end - end - end - private - - def normalize_time - self.hours += minutes / 60 - self.minutes = minutes % 60 - end + + require 'csv' + + belongs_to :user + + validates :date, :hours, :minutes, presence: true + validates :hours, numericality: { only_integer: true, greater_than_or_equal_to: 0 } + validates :minutes, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than: 60 } + + before_save :normalize_time + + PRAKTIKUMSTYPEN = %w[propädeutikum fachspezifikum] + ENTRY_ARTEN = %w[Praktikum Selbsterfahrung Supervision Fortbildung Semesterkosten] + + validates :praktikums_typ, inclusion: { in: PRAKTIKUMSTYPEN } + validates :entry_art, inclusion: { in: ENTRY_ARTEN } + validates :distance_km, numericality: { only_integer: true, greater_than_or_equal_to: 0 } + + after_initialize :set_default_date, if: :new_record? + + def set_default_date + self.date ||= Date.today + end + + def kilometer_pauschale + return 0 unless distance_km.present? + distance_km * 0.42 + end + + def self.total_kilometer_cost_by_year(user) + where(user: user) + .where.not(distance_km: nil) + .group(Arel.sql("DATE_PART('year', date)")) + .order(Arel.sql("DATE_PART('year', date) DESC")) + .pluck( + Arel.sql("DATE_PART('year', date)::int"), + Arel.sql("SUM(distance_km * 2 * 0.42)") + ).to_h + end + + def self.total_fortbildungskosten_by_year(user) + where(user: user, entry_art: 'Fortbildung') + .where.not(kosten: nil) + .group(Arel.sql("DATE_PART('year', date)")) + .order(Arel.sql("DATE_PART('year', date) DESC")) + .pluck(Arel.sql("DATE_PART('year', date)::int"), Arel.sql("SUM(kosten)")) + .to_h + end + + def self.total_selbsterfahrungskosten_by_year(user) + where(user: user, entry_art: 'Selbsterfahrung') + .where.not(kosten: nil) + .group(Arel.sql("DATE_PART('year', date)")) + .order(Arel.sql("DATE_PART('year', date) DESC")) + .pluck(Arel.sql("DATE_PART('year', date)::int"), Arel.sql("SUM(kosten)")) + .to_h + end + + def self.total_selbsterfahrungskosten_by_year(user) + where(user: user, entry_art: 'Selbsterfahrung') + .where.not(kosten: nil) + .group(Arel.sql("DATE_PART('year', date)")) + .order(Arel.sql("DATE_PART('year', date) DESC")) + .pluck(Arel.sql("DATE_PART('year', date)::int"), Arel.sql("SUM(kosten)")) + .to_h + end + + def self.total_supervision_by_year(user) + where(user: user, entry_art: 'Supervision') + .where.not(kosten: nil) + .group(Arel.sql("DATE_PART('year', date)")) + .order(Arel.sql("DATE_PART('year', date) DESC")) + .pluck(Arel.sql("DATE_PART('year', date)::int"), Arel.sql("SUM(kosten)")) + .to_h + end + + def self.total_semesterkosten_by_year(user) + where(user: user) + .where.not(kosten: nil) + .group(Arel.sql("DATE_PART('year', date)")) + .order(Arel.sql("DATE_PART('year', date) DESC")) + .pluck(Arel.sql("DATE_PART('year', date)::int"), Arel.sql("SUM(kosten)")) + .to_h + end + + def jahr + date.year + end + + def total_minutes + hours * 60 + minutes + end + + def self.to_csv + CSV.generate(headers: true, col_sep: ";") do |csv| + csv << %w[Datum Stunden Minuten Typ Art Kilometer User] + + all.each do |entry| + csv << [ + entry.date, + entry.hours, + entry.minutes, + entry.praktikums_typ, + entry.entry_art, + entry.distance_km, + entry.beschreibung, + entry.kosten, + entry.user.email + ] + end + end + end + + private + + def normalize_time + self.hours += minutes / 60 + self.minutes = minutes % 60 + end end