Add a printer job queue via the printer plugin

This commit is contained in:
Patrick Gansterer 2019-02-02 12:40:57 +01:00
parent 63e1541aa3
commit c955a6ee40
24 changed files with 561 additions and 1 deletions

View file

@ -0,0 +1,58 @@
class PrinterController < ApplicationController
include Concerns::SendOrderPdf
include Tubesock::Hijack
skip_before_filter :authenticate
before_filter :authenticate_printer
before_filter -> { require_plugin_enabled FoodsoftPrinter }
def socket
hijack do |tubesock|
tubesock.onopen do
tubesock.send_data unfinished_jobs
end
tubesock.onmessage do |data|
update_job data
tubesock.send_data unfinished_jobs
end
end
end
def show
job = PrinterJob.find(params[:id])
send_order_pdf job.order, job.document
end
private
def unfinished_jobs
{
unfinished_jobs: PrinterJob.pending.map(&:id)
}.to_json
end
def update_job(data)
json = JSON.parse data, symbolize_names: true
job = PrinterJob.unfinished.find_by_id(json[:id])
return unless job
if json[:state]
job.add_update! json[:state], json[:message]
end
job.finish! if json[:finish]
end
protected
def bearer_token
pattern = /^Bearer /
header = request.headers['Authorization']
header.gsub(pattern, '') if header && header.match(pattern)
end
def authenticate_printer
return head(:unauthorized) unless bearer_token
return head(:forbidden) if bearer_token != FoodsoftConfig[:printer_token]
end
end

View file

@ -0,0 +1,44 @@
class PrinterJobsController < ApplicationController
include Concerns::SendOrderPdf
before_filter -> { require_plugin_enabled FoodsoftPrinter }
def index
jobs = PrinterJob.includes(:printer_job_updates)
@pending_jobs = jobs.pending
@queued_jobs = jobs.queued
@finished_jobs = jobs.finished.order(finished_at: :desc).page(params[:page]).per(@per_page)
end
def create
order = Order.find(params[:order])
state = order.open? ? 'queued' : 'ready'
count = 0
PrinterJob.transaction do
%w(articles fax groups matrix).each do |document|
next unless FoodsoftConfig["printer_print_order_#{document}"]
job = PrinterJob.create! order: order, document: document, created_by: current_user
job.add_update! state
count += 1
end
end
redirect_to order, notice: t('.notice', count: count)
end
def show
@job = PrinterJob.find(params[:id])
end
def document
job = PrinterJob.find(params[:id])
send_order_pdf job.order, job.document
end
def destroy
job = PrinterJob.find(params[:id])
job.finish! current_user
redirect_to printer_jobs_path, notice: t('.notice')
rescue => error
redirect_to printer_jobs_path, t('errors.general_msg', msg: error.message)
end
end

View file

@ -0,0 +1,31 @@
class PrinterJob < ActiveRecord::Base
belongs_to :order
belongs_to :created_by, class_name: 'User', foreign_key: 'created_by_user_id'
belongs_to :finished_by, class_name: 'User', foreign_key: 'finished_by_user_id'
has_many :printer_job_updates
scope :finished, -> { where.not(finished_at: nil) }
scope :unfinished, -> { where(finished_at: nil).order(:id) }
scope :pending, -> { unfinished.includes(:order).where.not(orders: {state: 'open'}) }
scope :queued, -> { unfinished.includes(:order).where(orders: {state: 'open'}) }
def last_update_at
printer_job_updates.order(:created_at).last.try(&:created_at)
end
def last_update_state
printer_job_updates.order(:created_at).last.try(&:state)
end
def add_update!(state, message=nil)
return unless finished_at.nil?
PrinterJobUpdate.create! printer_job: self, state: state, message: message
end
def finish!(user=nil)
return unless finished_at.nil?
update_attributes finished_at: Time.now, finished_by: user
end
end

View file

@ -0,0 +1,5 @@
class PrinterJobUpdate < ActiveRecord::Base
belongs_to :printer_job
end

View file

@ -0,0 +1,7 @@
/ insert_after ':root:last-child'
= config_use_heading form, :use_printer do
= config_input form, :printer_token, as: :string, input_html: {class: 'input-xlarge'}
= config_input form, :printer_print_order_fax, as: :boolean
= config_input form, :printer_print_order_articles, as: :boolean
= config_input form, :printer_print_order_groups, as: :boolean
= config_input form, :printer_print_order_matrix, as: :boolean

View file

@ -0,0 +1,7 @@
/ insert_after 'erb:contains("title t(\'.title\'")'
- content_for :actionbar do
- if FoodsoftPrinter.enabled?
= link_to content_tag(:i, nil, class: 'icon-print'), printer_jobs_path(order: @order), method: :post,
class: "btn#{' btn-primary' unless @order.printer_jobs.any?}",
data: {confirm: @order.printer_jobs.any? && t('.confirm_create_printer_job') },
title: t('helpers.submit.printer_job.create')

View file

@ -0,0 +1,22 @@
.pull-right
- if @finished_jobs.total_pages > 1
.btn-group= items_per_page wrap: false
= pagination_links_remote @finished_jobs
%table.table.table-striped
%thead
%tr
%th= heading_helper(PrinterJob, :id)
%th= heading_helper(PrinterJob, :order)
%th= heading_helper(PrinterJob, :pickup)
%th= heading_helper(PrinterJob, :document)
%th= heading_helper(PrinterJob, :last_update_state)
%th= heading_helper(PrinterJob, :finished_at)
%tbody
- @finished_jobs.each do |j|
%tr
%td= link_to j.id, j
%td= link_to j.order.supplier.name, j.order
%td= format_date j.order.pickup
%td= link_to j.document, document_printer_job_path(j)
%td= j.last_update_state
%td= format_time j.finished_at

View file

@ -0,0 +1,47 @@
- title t('.title')
- unless @pending_jobs.empty? && @queued_jobs.empty?
.well
%h2
- if @pending_jobs.any?
=t '.pending'
- else
=t '.queued'
%table.table.table-striped
%thead
%tr
%th= heading_helper(PrinterJob, :id)
%th= heading_helper(PrinterJob, :order)
%th= heading_helper(PrinterJob, :pickup)
%th= heading_helper(PrinterJob, :document)
%th= heading_helper(PrinterJob, :last_update_at)
%th= heading_helper(PrinterJob, :last_update_state)
%th
%tbody
- @pending_jobs.each do |j|
%tr
%td= link_to j.id, j
%td= link_to j.order.supplier.name, j.order
%td= format_date j.order.pickup
%td= link_to j.document, document_printer_job_path(j)
%td= format_time j.last_update_at
%td= j.last_update_state
%td= link_to t('ui.delete'), j, method: :delete, data: {:confirm => t('ui.confirm_delete', name: j.id)},
class: 'btn btn-mini btn-danger'
- if @pending_jobs.any?
%tr
%td{colspan: 7}
%h2= t '.queued'
- @queued_jobs.each do |j|
%tr
%td= link_to j.id, j
%td= link_to j.order.supplier.name, j.order
%td= format_date j.order.pickup
%td= link_to j.document, document_printer_job_path(j)
%td= format_time j.last_update_at
%td= j.last_update_state
%td= link_to t('ui.delete'), j, method: :delete, data: {:confirm => t('ui.confirm_delete', name: j.id)},
class: 'btn btn-mini btn-danger'
%h2= t '.finished'
#jobsTable= render 'jobs'

View file

@ -0,0 +1 @@
$('#jobsTable').html('#{j(render('jobs'))}');

View file

@ -0,0 +1,36 @@
- title t('.title', id: @job.id)
%p
%b= heading_helper(PrinterJob, :created_by) + ':'
= show_user @job.created_by
%p
%b= heading_helper(PrinterJob, :order) + ':'
= @job.order.supplier.name
%p
%b= heading_helper(PrinterJob, :pickup) + ':'
= @job.order.pickup
%p
%b= heading_helper(PrinterJob, :document) + ':'
= @job.document
- if @job.finished_at
%p
%b= heading_helper(PrinterJob, :finished_at) + ':'
= format_time @job.finished_at
- if @job.finished_by
%p
%b= heading_helper(PrinterJob, :finished_by) + ':'
= show_user @job.finished_by
%table.table.table-striped
%thead
%tr
%th= heading_helper(PrinterJobUpdate, :created_at)
%th= heading_helper(PrinterJobUpdate, :state)
%th= heading_helper(PrinterJobUpdate, :message)
%tbody
- @job.printer_job_updates.each do |u|
%tr
%td= format_time u.created_at
%td= u.state
%td= u.message