Add a printer job queue via the printer plugin
This commit is contained in:
parent
63e1541aa3
commit
c955a6ee40
24 changed files with 561 additions and 1 deletions
1
Gemfile
1
Gemfile
|
@ -64,6 +64,7 @@ gem 'foodsoft_discourse', path: 'plugins/discourse'
|
|||
|
||||
# plugins not enabled by default
|
||||
#gem 'foodsoft_current_orders', path: 'plugins/current_orders'
|
||||
#gem 'foodsoft_printer', path: 'plugins/printer'
|
||||
#gem 'foodsoft_uservoice', path: 'plugins/uservoice'
|
||||
|
||||
|
||||
|
|
|
@ -649,6 +649,11 @@ de:
|
|||
pdf_font_size: Schriftgrösse
|
||||
pdf_page_size: Seitenformat
|
||||
price_markup: Foodcoop Marge
|
||||
printer_print_order_articles: Artikel PDF drucken
|
||||
printer_print_order_fax: Fax PDF drucken
|
||||
printer_print_order_groups: Gruppen PDF drucken
|
||||
printer_print_order_matrix: Matrix PDF drucken
|
||||
printer_token: Geheimer Token
|
||||
stop_ordering_under: Apfelpunkte Minimum
|
||||
tasks_period_days: Zeitintervall
|
||||
tasks_upfront_days: Im Voraus
|
||||
|
@ -662,6 +667,7 @@ de:
|
|||
use_iban: IBAN verwenden
|
||||
use_messages: Nachrichten
|
||||
use_nick: Benutzernamen verwenden
|
||||
use_printer: Drucker verwenden
|
||||
use_wiki: Wiki verwenden
|
||||
webstats_tracking_code: Code für Websiteanalysetool
|
||||
tabs:
|
||||
|
@ -1109,6 +1115,8 @@ de:
|
|||
submit:
|
||||
invite:
|
||||
create: Einladung verschicken
|
||||
printer_job:
|
||||
create: Druckauftrag erstellen
|
||||
message:
|
||||
create: Nachricht verschicken
|
||||
tasks:
|
||||
|
@ -1461,6 +1469,7 @@ de:
|
|||
manage: Bestellverwaltung
|
||||
ordering: Bestellen!
|
||||
pickups: Abholtage
|
||||
printer_jobs: Druckaufträge
|
||||
title: Bestellungen
|
||||
tasks: Aufgaben
|
||||
wiki:
|
||||
|
@ -1565,6 +1574,7 @@ de:
|
|||
confirm_end: |-
|
||||
Willst Du wirklich die Bestellung %{order} beenden?
|
||||
Es gibt kein zurück.
|
||||
confirm_create_printer_job: Für diese Bestellung wurde bereits ein Druckauftrag erstellt. Willst du einen neuen erstellen?
|
||||
confirm_send_to_supplier: Die Bestellung wurde bereit am %{when} zur Lieferantin geschickt. Willst du sie wirklich erneut schicken?
|
||||
create_invoice: Rechnung anlegen
|
||||
description1_order: "%{state} Bestellung von %{supplier} angelegt von %{who},"
|
||||
|
@ -1704,6 +1714,18 @@ de:
|
|||
nojs: Achtung, Cookies und Javascript müssen aktiviert sein! %{link} bitte abschalten.
|
||||
noscript: NoScript
|
||||
title: Foodsoft anmelden
|
||||
printer_jobs:
|
||||
create:
|
||||
notice: "%{count} Druckaufträge wurden erstellt."
|
||||
destroy:
|
||||
notice: Druckauftrag wurde gelöscht.
|
||||
index:
|
||||
finished: Beendet
|
||||
pending: Ausstehend
|
||||
queued: Warten auf den Bestellschluss
|
||||
title: Druckaufträge
|
||||
show:
|
||||
title: Druckauftrag %{id}
|
||||
shared:
|
||||
articles:
|
||||
ordered: Bestellt
|
||||
|
|
|
@ -652,6 +652,11 @@ en:
|
|||
pdf_font_size: Font size
|
||||
pdf_page_size: Page size
|
||||
price_markup: Foodcoop margin
|
||||
printer_print_order_articles: Print article PDF
|
||||
printer_print_order_fax: Print fax PDF
|
||||
printer_print_order_groups: Print group PDF
|
||||
printer_print_order_matrix: Print matrix PDF
|
||||
printer_token: Secret token
|
||||
stop_ordering_under: Minimum apple points
|
||||
tasks_period_days: Period
|
||||
tasks_upfront_days: Create upfront
|
||||
|
@ -665,6 +670,7 @@ en:
|
|||
use_iban: Use IBAN
|
||||
use_messages: Messages
|
||||
use_nick: Use nicknames
|
||||
use_printer: Use printer
|
||||
use_wiki: Enable wiki
|
||||
webstats_tracking_code: Tracking code
|
||||
tabs:
|
||||
|
@ -1126,6 +1132,8 @@ en:
|
|||
submit:
|
||||
invite:
|
||||
create: send invitation
|
||||
printer_job:
|
||||
create: create printer job
|
||||
message:
|
||||
create: send message
|
||||
tasks:
|
||||
|
@ -1487,6 +1495,7 @@ en:
|
|||
manage: Manage orders
|
||||
ordering: Place order!
|
||||
pickups: Pickup days
|
||||
printer_jobs: Printer jobs
|
||||
title: Orders
|
||||
tasks: Tasks
|
||||
wiki:
|
||||
|
@ -1591,6 +1600,7 @@ en:
|
|||
confirm_end: |-
|
||||
Do you really want to close the order %{order}?
|
||||
There is no going back.
|
||||
confirm_create_printer_job: A printer job for this order has been created already. Do you want to create a new one?
|
||||
confirm_send_to_supplier: The order has been sent to the supplier already on %{when}. Do you really want to send it again?
|
||||
create_invoice: Add invoice
|
||||
description1_order: "%{state} order from %{supplier} opened by %{who},"
|
||||
|
@ -1730,6 +1740,18 @@ en:
|
|||
nojs: Attention, cookies and javascript have to be activated! Please switch off %{link}.
|
||||
noscript: NoScript
|
||||
title: Foodsoft login
|
||||
printer_jobs:
|
||||
create:
|
||||
notice: Created %{count} printer jobs.
|
||||
destroy:
|
||||
notice: Printer job has been deleted.
|
||||
index:
|
||||
finished: Finished
|
||||
pending: Pending
|
||||
queued: Waiting for order to close
|
||||
title: Printer jobs
|
||||
show:
|
||||
title: Printer job %{id}
|
||||
shared:
|
||||
articles:
|
||||
ordered: Ordered
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
class CreatePrinterJobs < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :printer_jobs do |t|
|
||||
t.references :order
|
||||
t.string :document, null: false
|
||||
t.integer :created_by_user_id, null: false
|
||||
t.integer :finished_by_user_id
|
||||
t.datetime :finished_at, index: true
|
||||
end
|
||||
|
||||
create_table :printer_job_updates do |t|
|
||||
t.references :printer_job, null: false
|
||||
t.datetime :created_at, null: false
|
||||
t.string :state, null: false
|
||||
t.text :message
|
||||
end
|
||||
|
||||
add_index :printer_job_updates, [:printer_job_id, :created_at]
|
||||
end
|
||||
end
|
21
db/schema.rb
21
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20171201000000) do
|
||||
ActiveRecord::Schema.define(version: 20181201000000) do
|
||||
|
||||
create_table "article_categories", force: :cascade do |t|
|
||||
t.string "name", limit: 255, default: "", null: false
|
||||
|
@ -378,6 +378,25 @@ ActiveRecord::Schema.define(version: 20171201000000) do
|
|||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "printer_job_updates", force: :cascade do |t|
|
||||
t.integer "printer_job_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.string "state", null: false
|
||||
t.text "message"
|
||||
end
|
||||
|
||||
add_index "printer_job_updates", ["printer_job_id", "created_at"], name: "index_printer_job_updates_on_printer_job_id_and_created_at", using: :btree
|
||||
|
||||
create_table "printer_jobs", force: :cascade do |t|
|
||||
t.integer "order_id"
|
||||
t.string "document", null: false
|
||||
t.integer "created_by_user_id", null: false
|
||||
t.integer "finished_by_user_id"
|
||||
t.datetime "finished_at"
|
||||
end
|
||||
|
||||
add_index "printer_jobs", ["finished_at"], name: "index_printer_jobs_on_finished_at", using: :btree
|
||||
|
||||
create_table "settings", force: :cascade do |t|
|
||||
t.string "var", limit: 255, null: false
|
||||
t.text "value", limit: 65535
|
||||
|
|
61
plugins/printer/README.md
Normal file
61
plugins/printer/README.md
Normal file
|
@ -0,0 +1,61 @@
|
|||
FoodsoftPrinter
|
||||
=================
|
||||
|
||||
This plugin adds a printer queue to allow mebers to print PDF with one click.
|
||||
Usually a mini computer with a printer at a room in the foodcoop will wait for
|
||||
new printer jobs and prints them.
|
||||
|
||||
This plugin is not enabled by default. To install it, add uncomment the
|
||||
corresponding line in the `Gemfile`, or add:
|
||||
|
||||
```Gemfile
|
||||
gem 'foodsoft_printer', path: 'plugins/foodsoft_printer'
|
||||
```
|
||||
|
||||
This plugin introduces the foodcoop config option `printer_token`, which takes
|
||||
a random string for authentication at the endpoint. Additionally a set of
|
||||
PDF files can be selected, which will be generated when a print is triggered.
|
||||
|
||||
The communication with the printer client happens via two endpoints, which both
|
||||
require the `printer_token` as `Bearer` token in the `Authorization` header.
|
||||
* `/:foodcoop/printer/socket`: main WebSocket communication
|
||||
* `/:foodcoop/printer/:id`: HTTP GET for documents
|
||||
|
||||
The main communication happens via JSON messages via an WebSocket connection,
|
||||
which sends an array of docuement ids to the client, which need to be printed.
|
||||
Addionally the docuemnt can be downloaded as PDF via a separate endpoint.
|
||||
The client can updated the status of the documents by sending an object with
|
||||
the following keys to the server:
|
||||
* `id` (NBR, REQUIRED): id of the document, which should be updated
|
||||
* `state` (ENUM): the current sate of the printing progress.
|
||||
* `message` (STR, REQUIRES `state`): detailed description of the current state
|
||||
(e.g. download progress)
|
||||
* `finish` (BOOL): when set to `true` the job will be marked as done
|
||||
|
||||
The following values are valid for the `state` property:
|
||||
* `queued`: the document is not yet ready for printing
|
||||
* `ready`: the document is ready to be downloaded
|
||||
* `downloading`: transfer of the document is in progress
|
||||
* `pending`: download completed, waiting for the printer
|
||||
* `held`: e.g., for "PIN printing"
|
||||
* `processing`: printing is in progress
|
||||
* `stopped`: out of paper, etc.)
|
||||
* `cancelled`: the user stopped the action
|
||||
* `aborted`: the printer stopped the action
|
||||
* `completed`: print was successful
|
||||
|
||||
**Example**:
|
||||
A server sending `{"unfinished_jobs":[12,16]}` via WebSocket indicates that the
|
||||
two documents `12` and `16` are ready for printing. The client will request the
|
||||
first document from `/foodcoop/printer/12` and send it to the printer. The
|
||||
status can be updated by sending `{"id":12,"state":"pending"}` via WebSocket to
|
||||
the server. Sending `{"id":12,"state":"completed","finish":true}` as soon as
|
||||
when the printing succeded will mark the job done.
|
||||
|
||||
To use this plugin the webserver must support WebSockets. The current
|
||||
implementation uses socket hijack, which is not supported by `thin`. `puma`
|
||||
supports that, but might lead to other problems, since it's not well tested
|
||||
in combination with foodsoft. Please be careful when switching the webserver!
|
||||
|
||||
This plugin is part of the foodsoft package and uses the AGPL-3 license (see
|
||||
foodsoft's LICENSE for the full license text).
|
40
plugins/printer/Rakefile
Normal file
40
plugins/printer/Rakefile
Normal file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env rake
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
begin
|
||||
require 'rdoc/task'
|
||||
rescue LoadError
|
||||
require 'rdoc/rdoc'
|
||||
require 'rake/rdoctask'
|
||||
RDoc::Task = Rake::RDocTask
|
||||
end
|
||||
|
||||
RDoc::Task.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'FoodsoftPrinter'
|
||||
rdoc.options << '--line-numbers'
|
||||
rdoc.rdoc_files.include('README.rdoc')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
||||
load 'rails/tasks/engine.rake'
|
||||
|
||||
|
||||
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require 'rake/testtask'
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.libs << 'test'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = false
|
||||
end
|
||||
|
||||
|
||||
task :default => :test
|
58
plugins/printer/app/controllers/printer_controller.rb
Normal file
58
plugins/printer/app/controllers/printer_controller.rb
Normal 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
|
44
plugins/printer/app/controllers/printer_jobs_controller.rb
Normal file
44
plugins/printer/app/controllers/printer_jobs_controller.rb
Normal 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
|
31
plugins/printer/app/models/printer_job.rb
Normal file
31
plugins/printer/app/models/printer_job.rb
Normal 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
|
5
plugins/printer/app/models/printer_job_update.rb
Normal file
5
plugins/printer/app/models/printer_job_update.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class PrinterJobUpdate < ActiveRecord::Base
|
||||
|
||||
belongs_to :printer_job
|
||||
|
||||
end
|
|
@ -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
|
|
@ -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')
|
22
plugins/printer/app/views/printer_jobs/_jobs.html.haml
Normal file
22
plugins/printer/app/views/printer_jobs/_jobs.html.haml
Normal 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
|
47
plugins/printer/app/views/printer_jobs/index.html.haml
Normal file
47
plugins/printer/app/views/printer_jobs/index.html.haml
Normal 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'
|
1
plugins/printer/app/views/printer_jobs/index.js.haml
Normal file
1
plugins/printer/app/views/printer_jobs/index.js.haml
Normal file
|
@ -0,0 +1 @@
|
|||
$('#jobsTable').html('#{j(render('jobs'))}');
|
36
plugins/printer/app/views/printer_jobs/show.html.haml
Normal file
36
plugins/printer/app/views/printer_jobs/show.html.haml
Normal 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
|
11
plugins/printer/config/routes.rb
Normal file
11
plugins/printer/config/routes.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
Rails.application.routes.draw do
|
||||
scope '/:foodcoop' do
|
||||
resources :printer, only: [:show] do
|
||||
get :socket, on: :collection
|
||||
end
|
||||
|
||||
resources :printer_jobs, only: [:index, :create, :show, :destroy] do
|
||||
get :document, on: :member
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
class CreatePrinterJobs < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :printer_jobs do |t|
|
||||
t.references :order
|
||||
t.string :document, null: false
|
||||
t.integer :created_by_user_id, null: false
|
||||
t.integer :finished_by_user_id
|
||||
t.datetime :finished_at, index: true
|
||||
end
|
||||
|
||||
create_table :printer_job_updates do |t|
|
||||
t.references :printer_job, null: false
|
||||
t.datetime :created_at, null: false
|
||||
t.string :state, null: false
|
||||
t.text :message
|
||||
end
|
||||
|
||||
add_index :printer_job_updates, [:printer_job_id, :created_at]
|
||||
end
|
||||
end
|
22
plugins/printer/foodsoft_printer.gemspec
Normal file
22
plugins/printer/foodsoft_printer.gemspec
Normal file
|
@ -0,0 +1,22 @@
|
|||
$:.push File.expand_path("../lib", __FILE__)
|
||||
|
||||
# Maintain your gem's version:
|
||||
require "foodsoft_printer/version"
|
||||
|
||||
# Describe your gem and declare its dependencies:
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "foodsoft_printer"
|
||||
s.version = FoodsoftPrinter::VERSION
|
||||
s.authors = ["paroga"]
|
||||
s.email = ["paroga@paroga.com"]
|
||||
s.homepage = "https://github.com/foodcoops/foodsoft"
|
||||
s.summary = "Printer plugin for foodsoft."
|
||||
s.description = "Add a printer queue to foodsoft."
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"]
|
||||
s.test_files = Dir["test/**/*"]
|
||||
|
||||
s.add_dependency "rails"
|
||||
s.add_dependency "deface", "~> 1.0"
|
||||
s.add_dependency "tubesock"
|
||||
end
|
9
plugins/printer/lib/foodsoft_printer.rb
Normal file
9
plugins/printer/lib/foodsoft_printer.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
require 'foodsoft_printer/engine'
|
||||
require 'foodsoft_printer/order_printer_jobs'
|
||||
require 'tubesock'
|
||||
|
||||
module FoodsoftPrinter
|
||||
def self.enabled?
|
||||
FoodsoftConfig[:use_printer]
|
||||
end
|
||||
end
|
26
plugins/printer/lib/foodsoft_printer/engine.rb
Normal file
26
plugins/printer/lib/foodsoft_printer/engine.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
module FoodsoftPrinter
|
||||
class Engine < ::Rails::Engine
|
||||
def navigation(primary, context)
|
||||
return unless FoodsoftPrinter.enabled?
|
||||
unless primary[:orders].nil?
|
||||
sub_nav = primary[:orders].sub_navigation
|
||||
sub_nav.items <<
|
||||
SimpleNavigation::Item.new(primary, :printer_jobs, I18n.t('navigation.orders.printer_jobs'), context.printer_jobs_path)
|
||||
end
|
||||
end
|
||||
|
||||
def default_foodsoft_config(cfg)
|
||||
cfg[:use_printer] = false
|
||||
end
|
||||
|
||||
initializer 'foodsoft_printer.order_printer_jobs' do |app|
|
||||
if Rails.configuration.cache_classes
|
||||
OrderPrinterJobs.install
|
||||
else
|
||||
ActionDispatch::Reloader.to_prepare do
|
||||
OrderPrinterJobs.install
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
26
plugins/printer/lib/foodsoft_printer/order_printer_jobs.rb
Normal file
26
plugins/printer/lib/foodsoft_printer/order_printer_jobs.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
module FoodsoftPrinter
|
||||
|
||||
module OrderPrinterJobs
|
||||
def self.included(base) # :nodoc:
|
||||
base.class_eval do
|
||||
has_many :printer_jobs, dependent: :destroy
|
||||
|
||||
alias foodsoft_printer_orig_finish! finish!
|
||||
|
||||
def finish!(user)
|
||||
foodsoft_printer_orig_finish!(user)
|
||||
unless finished?
|
||||
printer_jobs.unfinished.each do |job|
|
||||
job.add_update! 'ready'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.install
|
||||
Order.send :include, self
|
||||
end
|
||||
end
|
||||
|
||||
end
|
3
plugins/printer/lib/foodsoft_printer/version.rb
Normal file
3
plugins/printer/lib/foodsoft_printer/version.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
module FoodsoftPrinter
|
||||
VERSION = "0.0.1"
|
||||
end
|
Loading…
Reference in a new issue