Skip to content

Commit d0df3a0

Browse files
Thomas von DeyenJeff Dutil
Thomas von Deyen
authored and
Jeff Dutil
committed
Move invoice updating into order model.
Remove selenium support and update poltergeist. Adds new settings store_pdf and storage_path Adds pdf file generation to order model. The order can now render itself to pdf. Delegate order controller show :pdf action to order. The controller now tells the order to render itself as pdf and to store it, if enabled. Fix pdf templates. Add javascript injection to install generator. Mention store pdf feature in readme Updates invoice number on pdf render in controller. Like before: it sets the invoice number to next incremential value, if enabled. Stub configuration for more reliable tests Fixes #80
1 parent b0e476a commit d0df3a0

32 files changed

+397
-110
lines changed

.travis.yml

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ rvm:
66
sudo: false
77
cache: bundler
88
before_script:
9-
- sh -e /etc/init.d/xvfb start
10-
- export DISPLAY=:99.0
119
- bundle exec rake test_app
1210
script:
1311
- bundle exec rspec spec

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ Enjoy! Now allow to generate invoices with sequential numbers.
5757
Spree::PrintInvoice::Config.set(prawn_options: { page_layout: :landscape, page_size: 'A4', margin: [50, 100, 150, 200] })
5858
```
5959

60+
8. Enable PDF storage feature
61+
62+
PDF files can be stored to disk. This is very handy, if you want to send these files as email attachment.
63+
64+
```ruby
65+
Spree::PrintInvoice::Config.set(store_pdf: true) # Default: false
66+
Spree::PrintInvoice::Config.set(storage_path: 'pdfs/orders') # Default: tmp/order_prints
67+
```
68+
69+
*) Inside the `storage_path` a folder for each template will be created. Files will be saved with order number respectively invoice number as file name.
70+
6071
## Customize templates
6172

6273
In order to customize the build in invoice and packaging slip templates you need to copy them into your app:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
$ ->
2+
storage_path_field = $('#storage_path')
3+
4+
$('#store_pdf').click ->
5+
storage_path_field.prop('disabled', !$(this).prop('checked'))
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
//= require spree/backend
2+
//= require ./print_invoice_settings

app/controllers/spree/admin/orders_controller_decorator.rb

+11-9
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@ module Admin
55

66
def show
77
load_order
8+
89
respond_with(@order) do |format|
910
format.pdf do
10-
template = params[:template] || 'invoice'
11-
update_sequential_number_for(@order) if template == 'invoice'
12-
render layout: false, template: "spree/admin/orders/#{template}.pdf.prawn"
11+
@order.update_invoice_number!
12+
13+
send_data @order.pdf_file(pdf_template_name),
14+
type: 'application/pdf', disposition: 'inline'
1315
end
1416
end
1517
end
1618

1719
private
1820

19-
def update_sequential_number_for(order)
20-
return unless Spree::PrintInvoice::Config.use_sequential_number?
21-
return unless order.invoice_number.present?
22-
order.invoice_number = Spree::PrintInvoice::Config.increase_invoice_number
23-
order.invoice_date = Date.today
24-
order.save!
21+
def pdf_template_name
22+
pdf_template_name = params[:template] || 'invoice'
23+
if !Spree::PrintInvoice::Config.print_templates.include?(pdf_template_name)
24+
raise Spree::PrintInvoice::UnsupportedTemplateError.new(pdf_template_name)
25+
end
26+
pdf_template_name
2527
end
2628
end
2729
end

app/models/spree/order_decorator.rb

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
Spree::Order.class_eval do
2+
3+
# Updates +invoice_number+ without calling ActiveRecord callbacks
4+
#
5+
# Only updates if number is not already present and if
6+
# +Spree::PrintInvoice::Config.next_number+ is set and greater than zero.
7+
#
8+
# Also sets +invoice_date+ to current date.
9+
#
10+
def update_invoice_number!
11+
return unless Spree::PrintInvoice::Config.use_sequential_number?
12+
return if invoice_number.present?
13+
14+
update_columns(
15+
invoice_number: Spree::PrintInvoice::Config.increase_invoice_number,
16+
invoice_date: Date.today
17+
)
18+
end
19+
20+
# Returns the given template as pdf binary suitable for Rails send_data
21+
#
22+
# If the file is already present it returns this
23+
# else it generates a new file, stores and returns this.
24+
#
25+
# You can disable the pdf file generation with setting
26+
#
27+
# Spree::PrintInvoice::Config.store_pdf to false
28+
#
29+
def pdf_file(template)
30+
if Spree::PrintInvoice::Config.store_pdf
31+
send_or_create_pdf(template)
32+
else
33+
render_pdf(template)
34+
end
35+
end
36+
37+
# = The PDF filename
38+
#
39+
# Tries to take invoice_number attribute.
40+
# If this is not present it takes the order number.
41+
#
42+
def pdf_filename
43+
invoice_number.present? ? invoice_number : number
44+
end
45+
46+
# = PDF file path for template name
47+
#
48+
def pdf_file_path(template)
49+
Rails.root.join(pdf_storage_path(template), "#{pdf_filename}.pdf")
50+
end
51+
52+
# = PDF storage folder path for given template name
53+
#
54+
# Configure the storage path with +Spree::PrintInvoice::Config.storage_path+
55+
#
56+
# Each template type gets it own pluralized folder inside
57+
# of +Spree::PrintInvoice::Config.storage_path+
58+
#
59+
# == Example:
60+
#
61+
# pdf_storage_path('invoice') => "tmp/pdf_prints/invoices"
62+
#
63+
# Creates the folder if it's not present yet.
64+
#
65+
def pdf_storage_path(template)
66+
storage_path = Rails.root.join(Spree::PrintInvoice::Config.storage_path, template.pluralize)
67+
FileUtils.mkdir_p(storage_path)
68+
storage_path
69+
end
70+
71+
# Renders the prawn template for give template name in context of ActionView.
72+
#
73+
# Prawn templates need to be placed in +app/views/spree/admin/orders/+ folder.
74+
#
75+
# Assigns +@order+ instance variable
76+
#
77+
def render_pdf(template)
78+
ActionView::Base.new(
79+
ActionController::Base.view_paths,
80+
{order: self}
81+
).render(template: "spree/admin/orders/#{template}.pdf.prawn")
82+
end
83+
84+
private
85+
86+
# Sends stored pdf for given template from disk.
87+
#
88+
# Renders and stores it if it's not yet present.
89+
#
90+
def send_or_create_pdf(template)
91+
file_path = pdf_file_path(template)
92+
93+
unless File.exist?(file_path)
94+
File.open(file_path, "wb") { |f| f.puts render_pdf(template) }
95+
end
96+
97+
IO.binread(file_path)
98+
end
99+
end

app/views/spree/admin/orders/invoice.pdf.prawn

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ define_grid(columns: 5, rows: 8, gutter: 10)
66
# HEADER
77
repeat(:all) do
88
im = Rails.application.assets.find_asset(Spree::PrintInvoice::Config[:logo_path])
9-
if File.exist? im.pathname
9+
10+
if im && File.exist?(im.pathname)
1011
image im, vposition: :top, height: 40, scale: Spree::PrintInvoice::Config[:logo_scale]
1112
end
1213

app/views/spree/admin/orders/packaging_slip.pdf.prawn

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ define_grid(columns: 5, rows: 8, gutter: 10)
66
# HEADER
77
repeat(:all) do
88
im = Rails.application.assets.find_asset(Spree::PrintInvoice::Config[:logo_path])
9-
if File.exist? im.pathname
9+
if im && File.exist?(im.pathname)
1010
image im, vposition: :top, height: 40, scale: Spree::PrintInvoice::Config[:logo_scale]
1111
end
1212

@@ -19,7 +19,7 @@ repeat(:all) do
1919

2020
text Spree.t(:invoice_number, number: @order.invoice_number, scope: :print_invoice), align: :right
2121
move_down 2
22-
text "#{Spree.t(:invoice_date)} #{I18n.l @order.invoice_date}", align: :right
22+
text "#{Spree.t(:invoice_date, scope: :print_invoice)} #{I18n.l @order.invoice_date}", align: :right
2323

2424
else
2525

app/views/spree/admin/print_invoice_settings/edit.html.erb

+14
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@
6666
<%= label_tag :logo_scale, Spree.t(:logo_scale, scope: [:print_invoice, :preferences]) %>
6767
<%= number_field_tag(:logo_scale, Spree::PrintInvoice::Config[:logo_scale], in: 1...101, class: 'form-control') %>
6868
</div>
69+
70+
<div class="form-group">
71+
<div class="checkbox">
72+
<%= label_tag :store_pdf do %>
73+
<%= preference_field_tag(:store_pdf, Spree::PrintInvoice::Config[:store_pdf], type: :boolean) %>
74+
<%= Spree.t(:store_pdf, scope: [:print_invoice, :preferences]) %>
75+
<% end %>
76+
</div>
77+
</div>
78+
79+
<div class="form-group">
80+
<%= label_tag :storage_path, Spree.t(:storage_path, scope: [:print_invoice, :preferences]) %>
81+
<%= preference_field_tag(:storage_path, Spree::PrintInvoice::Config[:storage_path], class: 'form-control', disabled: !Spree::PrintInvoice::Config[:store_pdf]) %>
82+
</div>
6983
</fieldset>
7084
</div>
7185

config/locales/de.yml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ de:
3131
font_face: Schriftart
3232
font_size: Schriftgröße
3333
logo_scale: Logo-Skalierung
34+
store_pdf: PDF-Dateien speichern
35+
storage_path: Speicherort für PDF-Dateien
3436
settings: Rechnungsdruck-Einstellungen
3537
unprocessed: offene
3638
vat: MwSt. nicht anwendbar

config/locales/en.yml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ en:
3131
font_face: Font Face
3232
font_size: Font Size
3333
logo_scale: Logo Scale
34+
store_pdf: Store PDF files
35+
storage_path: PDF storage path
3436
settings: Print Invoice Settings
3537
unprocessed: Unprocessed
3638
vat: VAT not applicable

config/locales/es.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ es:
3030
return_message: Mensaje de vuelta del pedido
3131
font_face: Tipo de letra
3232
font_size: Tamaño de letra
33-
logo_scale: Eescala de Logo
33+
store_pdf: Store PDF files
34+
storage_path: PDF storage path
3435
settings: Configuración de impresión de facturas
3536
unprocessed: No procesado
3637
vat: IVA no aplicable

config/locales/fr.yml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ fr:
3131
font_face: Face à font
3232
font_size: Taille de font
3333
logo_scale: Échelle de logo
34+
store_pdf: Store PDF files
35+
storage_path: PDF storage path
3436
settings: Les paramètres d'impression des factures
3537
unprocessed: Non traité
3638
vat: "TVA non applicable, article 293 B du Code Général des Impôts"

config/locales/sv.yml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ sv:
3131
font_face: Typsnitt
3232
font_size: Typsnitt storlek
3333
logo_scale: Logo skala
34+
store_pdf: Store PDF files
35+
storage_path: PDF storage path
3436
settings: Utskrift inställningar
3537
unprocessed: Obearbetad
3638
vat: Moms inte tillämpligt

lib/generators/spree_print_invoice/install/install_generator.rb

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ module Generators
33
class InstallGenerator < Rails::Generators::Base
44
class_option :auto_run_migrations, type: :boolean, default: true
55

6+
def add_javascripts
7+
append_file "vendor/assets/javascripts/spree/backend/all.js", "//= require spree/backend/spree_print_invoice\n"
8+
end
9+
610
def add_migrations
711
run 'bundle exec rake railties:install:migrations FROM=spree_print_invoice'
812
end

lib/prawn_handler.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ def register
1111
alias_method :register!, :register
1212

1313
def call(template)
14-
%(extend #{DocumentProxy}; #{template.source}; pdf.render)
14+
<<-PDF
15+
extend #{DocumentProxy}
16+
#{template.source}
17+
pdf.render
18+
PDF
1519
end
1620
end
1721

lib/spree/print_invoice_setting.rb

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class PrintInvoiceSetting < Preferences::Configuration
1414
preference :logo_scale, :integer, default: 50
1515
preference :font_face, :string, default: 'Helvetica'
1616
preference :font_size, :integer, default: 9
17+
preference :store_pdf, :boolean, default: false
18+
preference :storage_path, :string, default: 'tmp/order_prints'
1719

1820
def page_sizes
1921
::PDF::Core::PageGeometry::SIZES.keys
@@ -46,5 +48,9 @@ def font_sizes
4648
def logo_scaling
4749
logo_scale.to_f / 100
4850
end
51+
52+
def print_templates
53+
get_preference(:print_buttons).split(',').map(&:strip)
54+
end
4955
end
5056
end

lib/spree_print_invoice.rb

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,9 @@
22
require 'spree_print_invoice/engine'
33
require 'spree_print_invoice/version'
44
require 'prawn_handler'
5-
require 'coffee_script'
5+
require 'spree_print_invoice/errors'
66

77
module Spree
88
module PrintInvoice
9-
module_function
10-
11-
def config(*)
12-
yield(Spree::PrintInvoice::Config)
13-
end
149
end
1510
end

lib/spree_print_invoice/errors.rb

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module Spree
2+
module PrintInvoice
3+
class UnsupportedTemplateError < StandardError
4+
def initialize(template_name)
5+
@template_name = template_name
6+
end
7+
8+
def message
9+
"#{@template_name} is an unsupported pdf template name! \
10+
Please use one of #{Spree::PrintInvoice::Config.print_templates}."
11+
end
12+
end
13+
end
14+
end

spec/controllers/spree/admin/order_controller_decorator_spec.rb

-12
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
RSpec.describe Spree::Admin::OrdersController, type: :controller do
2+
stub_authorization!
3+
4+
let!(:order) { create(:order_ready_to_ship) }
5+
6+
before do
7+
allow(controller).to receive(:load_order)
8+
controller.instance_variable_set('@order', order)
9+
end
10+
11+
describe '#show as :pdf' do
12+
it 'returns http success' do
13+
spree_get :show, id: order.number, format: :pdf
14+
expect(response).to be_success
15+
end
16+
17+
context 'with next_number set' do
18+
before do
19+
allow(Spree::PrintInvoice::Config).to receive(:next_number).and_return(100)
20+
end
21+
22+
it 'sets the invoice number' do
23+
expect {
24+
spree_get :show, id: order.number, format: :pdf
25+
}.to change(order, :invoice_number)
26+
end
27+
end
28+
29+
context 'with wrong template name' do
30+
it 'raises error' do
31+
expect {
32+
spree_get :show, id: order.number, format: :pdf, template: 'foo'
33+
}.to raise_error(Spree::PrintInvoice::UnsupportedTemplateError)
34+
end
35+
end
36+
37+
context 'with correct template name' do
38+
it 'renders pdf for given template.' do
39+
spree_get :show, id: order.number, format: :pdf, template: 'invoice'
40+
expect(response).to be_success
41+
end
42+
end
43+
end
44+
end

0 commit comments

Comments
 (0)