class Job < ApplicationRecord belongs_to :operator, class_name: 'User', optional: true belongs_to :costumer, class_name: 'User', optional: true has_one_attached :pdf, dependent: :purge validates_presence_of :costumer_firstname, :costumer_lastname, :privacy_policy_accepted, :pdf validate :acceptable_pdf before_save :update_printed_at, if: :will_save_change_to_status? before_save :update_paid_at, if: :will_save_change_to_status? before_save :update_status_changed_at, if: :will_save_change_to_status? # TODO: works only when job is created. Should move analyzer to activestorage :https://discuss.rubyonrails.org/t/active-storage-in-production-lessons-learned-and-in-depth-look-at-how-it-works/83289 after_create_commit :analyze_pdf # NOTE: Multiple status if paing before brinting? enum status: { open: 0, printing: 1, ready_for_pickup: 2, paid: 3, canceled: 4 } # NOTE: only named status are returned because of WHERE/IN clause for the enum values scope :in_status_order, -> { in_order_of(:status, %w[open printing ready_for_pickup paid canceled]) } scope :created_today, -> { created_on_day(Time.now) } scope :created_on_day, lambda { |date| where('created_at >= ? AND created_at <= ?', date.beginning_of_day, date.end_of_day) } scope :upgraded_today, -> { upgraded_on_day(Time.now) } scope :upgraded_on_day, lambda { |date| where('upgraded_at >= ? AND upgraded_at <= ?', date.beginning_of_day, date.end_of_day) } # Returns all jobs with status: open print ready_for_pickup and jobs from today with status: paid canceled # paid: only updated_at today # canceled: only updated_at today def self.currently_working_on # NOTE: use Time.now instead of Date.today to take the timezone into account where(status: %i[open printing ready_for_pickup]) .or(Job.where(status: %i[paid canceled]) .where('status_changed_at >= ?', Time.now.beginning_of_day)) # .in_status_order .order(created_at: :desc) .order(:costumer_firstname, :costumer_lastname) .with_attached_pdf # scope from activestorage for .includes(pdf_attachment: :blob) # .references(:pdf_attachment, :blob) # creates big join table end def fullname [costumer_firstname, ' ', costumer_lastname].join end def acceptable_pdf return unless pdf.attached? acceptable_types = ['application/pdf'] errors.add(:pdf, 'is too big') unless pdf.blob.byte_size <= 100.megabyte errors.add(:pdf, 'must be a PDF') unless acceptable_types.include?(pdf.content_type) end def able_to_cancel? open? end # cancel job only if it is still open def canceled! self.status = :canceled if open? save end private def update_printed_at self.printed_at = Time.now if ready_for_pickup? || (paid? && printed_at.nil?) end def update_paid_at self.paid_at = Time.now if paid? end def update_status_changed_at self.status_changed_at = Time.now end def analyze_pdf # return unless pdf.attached? && pdf.new_record? # TODO: add any check if attachment has changed # pdfs.each do |pdf| pdf.blob.open do |file| self.number_of_plans_a0 = 0 self.number_of_plans_a1 = 0 self.number_of_plans_a2 = 0 self.number_of_plans_a3 = 0 self.costum_qm_plan = 0 # file = ActiveStorage::Blob.service.path_for(pdf.key).to_s pdf_analyzer = Services::PdfAnalyzer.new(file) pdf_analyzer.analyze self.number_of_plans_a0 += pdf_analyzer.pages_a0 self.number_of_plans_a1 += pdf_analyzer.pages_a1 self.number_of_plans_a2 += pdf_analyzer.pages_a2 self.number_of_plans_a3 += pdf_analyzer.pages_a3 self.costum_qm_plan += pdf_analyzer.costum_qm save end # end end end