require "rqrcode" require "csv" class Item < ApplicationRecord belongs_to :category belongs_to :user, optional: true # Optional, falls im Raum oder Lager belongs_to :room, optional: true # Optional, falls beim User oder Lager has_many :assignment_logs, dependent: :destroy validates :name, :sku, presence: true validates :sticker_id, :serial_number, presence: true, uniqueness: true # Validierung: Darf nicht gleichzeitig einem User UND einem Raum gehören validate :either_user_or_room # Überwacht Besitzer- oder Raumwechsel für die Historie before_save :track_assignment_changes, if: -> { will_save_change_to_user_id? || will_save_change_to_room_id? } def generate_qr_code return if sticker_id.blank? # Erzeugt das QR-Code-Objekt basierend auf deiner vorgedruckten Sticker-ID qrcode = RQRCode::QRCode.new(sticker_id.to_s) # Rendert den QR-Code als SVG-Vektorgrafik (perfekt scharf für Bildschirme) qrcode.as_svg( color: "000", # Farbe: Schwarz shape_rendering: "crispEdges", # Erzwingt scharfe Kanten im Browser module_size: 4, # Kompakte Größe standalone: true, use_path: true ).html_safe # Sagt Rails, dass das HTML unbedenklich ausgegeben werden darf end def self.to_csv # Die Spaltenüberschriften, die in der Excel-Datei erscheinen sollen headers = [ "ID", "Artikelname", "SKU", "Seriennummer", "Sticker_ID", "Einkaufspreis", "Kategorie", "Aktueller_Standort", "Notizen", "Registriert_am" ] CSV.generate(headers: true, col_sep: ";", encoding: "UTF-8") do |csv| # 1. Kopfzeile schreiben csv << headers # 2. Datenzeilen schreiben (includes verhindert langsame N+1 Datenbankabfragen) all.includes(:category, :user, :room).each do |item| # Dynamischen Standort-Text ermitteln current_location = if item.user.present? "👤 #{item.user.name}" elsif item.room.present? "📍 #{item.room.name_with_building}" else "📦 Im Hauptlager" end csv << [ item.id, item.name, item.sku, item.serial_number, item.sticker_id, item.price, item.category&.name, current_location, item.notes, item.created_at.strftime("%d.%m.%Y %H:%M") ] end end end private def either_user_or_room if user_id.present? && room_id.present? errors.add(:base, "Ein Artikel kann nicht gleichzeitig einem Benutzer und einem Raum zugewiesen sein.") end end def track_assignment_changes # 1. Altes Log-Buch schließen, falls es eine vorherige Zuweisung gab if user_id_was.present? || room_id_was.present? last_log = assignment_logs.find_by(user_id: user_id_was, room_id: room_id_was, returned_at: nil) last_log&.update(returned_at: Time.current) end # 2. Neues Log-Buch öffnen für den neuen Inhaber oder den neuen Raum if user_id.present? || room_id.present? assignment_logs.build(user_id: user_id, room_id: room_id, assigned_at: Time.current) end end end