165 lines
5.7 KiB
Ruby
165 lines
5.7 KiB
Ruby
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
|
|
# validates_numericality_of {:number_of_plans_a0,:number_of_plans_a1, :number_of_plans_a2, :number_of_plans_a3}, greater_than_or_equal_to: 0
|
|
validates :number_of_plans_a0, :number_of_plans_a1, :number_of_plans_a2, :number_of_plans_a3, numericality: { greater_than_or_equal_to: 0 }
|
|
|
|
|
|
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?
|
|
before_save :set_cost_qm
|
|
before_save :calc_cost, if: :printed_pages_changes?
|
|
|
|
# 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
|
|
# https://redgreen.no/2021/01/24/custom-analyzer-for-activestorage.html
|
|
after_create_commit :analyze_pdf
|
|
|
|
# NOTE: Multiple status if paing before brinting?
|
|
enum :status, {
|
|
open: 0,
|
|
printing: 1,
|
|
pickup: 2,
|
|
paid: 3,
|
|
canceled: 4
|
|
}
|
|
|
|
AVAILABLE_PAGE_FORMATS = [ :a0, :a1, :a2, :a3 ]
|
|
|
|
# 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 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 :updated_today, -> { updated_on_day(Time.now) }
|
|
scope :updated_on_day, lambda { |date|
|
|
where("updated_at >= ? AND updated_at <= ?", date.beginning_of_day, date.end_of_day)
|
|
}
|
|
scope :status_changed_today, -> { status_changed_on_day(Time.now) }
|
|
scope :status_changed_on_day, lambda { |date|
|
|
where("status_changed_at >= ? AND status_changed_at <= ?", date.beginning_of_day, date.end_of_day)
|
|
}
|
|
# Returns all jobs with status: open print 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 pickup])
|
|
.or(Job.where(status: %i[paid canceled])
|
|
.where("status_changed_at >= ?", Time.now.beginning_of_day))
|
|
# .in_status_order
|
|
.order(created_at: :asc)
|
|
# .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 self.paidcanceled
|
|
Job.where(status: %i[paid canceled])
|
|
end
|
|
|
|
def costumer_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? || printing?
|
|
# TODO: different check for operator and admin
|
|
end
|
|
|
|
# cancel job only if it is still open
|
|
def canceled!
|
|
if able_to_cancel?
|
|
self.status = :canceled
|
|
self.printed_at = nil
|
|
self.paid_at = nil
|
|
save
|
|
end
|
|
end
|
|
|
|
def increment_page(din)
|
|
return false unless AVAILABLE_PAGE_FORMATS.include?(din.to_sym)
|
|
public_send("number_of_plans_#{din}=", public_send("number_of_plans_#{din}") + 1) if respond_to? "number_of_plans_#{din}="
|
|
save
|
|
end
|
|
|
|
def decrement_page(din)
|
|
return false unless AVAILABLE_PAGE_FORMATS.include?(din.to_sym)
|
|
public_send("number_of_plans_#{din}=", public_send("number_of_plans_#{din}") - 1) if respond_to? "number_of_plans_#{din}="
|
|
save
|
|
end
|
|
|
|
private
|
|
|
|
def printed_pages_changes?
|
|
costum_qm_plan_previously_changed? || number_of_plans_a0_changed? || number_of_plans_a1_changed? || number_of_plans_a2_changed? || number_of_plans_a3_changed?
|
|
end
|
|
|
|
def update_printed_at
|
|
self.printed_at = Time.now if 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 calc_cost
|
|
self.cost = (number_of_plans_a0 * cost_qm) + (number_of_plans_a1 * cost_qm / 2) +
|
|
(number_of_plans_a2 * cost_qm / 4) + (number_of_plans_a3 * cost_qm / 8) +
|
|
(costum_qm_plan * cost_qm)
|
|
end
|
|
|
|
def set_cost_qm
|
|
# TODO: get cost from global settings
|
|
self.cost_qm = 7
|
|
end
|
|
|
|
def analyze_pdf
|
|
# return unless pdf.attached? && pdf.new_record?
|
|
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
|
|
|
|
# TODO: add any check if attachment has changed
|
|
|
|
# pdfs.each do |pdf|
|
|
pdf.blob.open do |file|
|
|
# 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
|
|
end
|
|
# end
|
|
calc_cost
|
|
save
|
|
end
|
|
end
|