Files
vault171/app/models/item.rb
David Böhm fd3149b13f
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
CI / system-test (push) Has been cancelled
Added condition badge in show and removed in_use
2026-05-30 01:45:23 +02:00

144 lines
4.5 KiB
Ruby

require "rqrcode"
require "csv"
class Item < ApplicationRecord
# NEU: Erlaubt es Rails, diese Formularfelder temporär im Speicher zu halten,
# ohne dass dafür Spalten in der Datenbank existieren müssen.
attr_accessor :user_name, :room_name
enum :condition, {
unknown: "unknown",
new_item: "new_item",
as_new: "as_new",
used: "used",
heavily_used: "heavily_used",
defective: "defective"
}
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
# Holt die saubere Übersetzung vollautomatisch über die Rails-Konvention
# In app/models/item.rb
def human_condition
# Holt den nackten String-Wert direkt aus der Spalte
current_condition = self[:condition]
return nil if current_condition.blank?
Item.human_attribute_name("conditions.#{current_condition}")
end
# 1. Ermittelt den abstrakten Standort-Typen für das Badge
def location_badge_type
if user_id.present?
"user"
elsif room_id.present?
"room"
else
"storage"
end
end
# 2. Liefert den passenden Text für das Standort-Badge
def location_badge_label(short_room: false)
if user.present?
user.name
elsif room.present?
short_room ? room.name : room.name_with_building
else
"Hauptlager"
end
end
def condition_badge_type
condition
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 (Egal ob es bei einem User oder in einem Raum war)
# Wir suchen nach dem Log, das noch kein Rückgabedatum hat (returned_at: nil)
active_log = assignment_logs.find_by(returned_at: nil)
active_log&.update(returned_at: Time.current)
# 2. Neues Log-Buch öffnen
if user_id.present? || room_id.present?
# Zustand A: Zuweisung an Mitarbeiter oder Raum
assignment_logs.build(user_id: user_id, room_id: room_id, assigned_at: Time.current)
else
# Zustand B: Weder User noch Raum hinterlegt -> Das Gerät wandert ins Hauptlager!
# Wir lassen user_id und room_id auf nil, was im Logbuch "Hauptlager" bedeutet
assignment_logs.build(assigned_at: Time.current)
end
end
end