payday 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6880a9809ee7df8e384b8decd0496858eb7ebb32
4
- data.tar.gz: 51bf1bb2e4c33baef16308e4f85b9f2915579d00
3
+ metadata.gz: c63a9378b3f1a7e552dacce10b9b6261bd0eaec9
4
+ data.tar.gz: 144ae033085831b2035a185f0e3c3db491be1e19
5
5
  SHA512:
6
- metadata.gz: 22077148a2506af490538950d278c8afc1bdc755faac7b02e0cf449bab1824481006be542b41b3e6992fb0f651759d7752fd10ea4101c042c75955d2fa264d48
7
- data.tar.gz: 5440e42e22b128aef4109c6986e15d73d993562c35df550431864c188fdfb1f9fbe8b9cc6868d749170197b9dc93a8329969b01346d85f8d7e11760be8dfdeb2
6
+ metadata.gz: cc86262b5750704fd33c9f4aefe8aa3a396bc8da0491e1f58865525688500b70b1233c1189b181ba7d58dc1c9d2970d7ad5e821bf008d9012637d6b58469920d
7
+ data.tar.gz: a7c8d4b0bf431d03eca023028268ba7faf96a9691b1372edbbd4325ea43fdf525f90807977b23839ae114cb01bd1bc744e3e9d366a7140e566246a5d550aff34
@@ -0,0 +1,8 @@
1
+ Style/StringLiterals:
2
+ EnforcedStyle: double_quotes
3
+
4
+ Style/StringLiteralsInInterpolation:
5
+ EnforcedStyle: double_quotes
6
+
7
+ Style/AlignParameters:
8
+ EnforcedStyle: with_first_parameter
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.1.4 (2015-05-29)
4
+
5
+ * Bumped money gem to 6.5 (was 6.1.1)
6
+ * Bumped i18n gem to 0.7 (was 0.6.11)
7
+ * Added German translation for invoice date.
8
+
3
9
  ## 1.1.3 (2015-01-02)
4
10
 
5
11
  * Loosened requirements on Money gem.
data/Rakefile CHANGED
@@ -1,12 +1,12 @@
1
- require 'bundler'
1
+ require "bundler"
2
2
 
3
- require 'rake'
4
- require 'rake/testtask'
3
+ require "rake"
4
+ require "rake/testtask"
5
5
 
6
- task :default => :test
6
+ task default: :test
7
7
 
8
8
  Bundler::GemHelper.install_tasks
9
9
 
10
10
  Rake::TestTask.new do |t|
11
- t.test_files = FileList['test/**/*_test.rb']
12
- end
11
+ t.test_files = FileList["test/**/*_test.rb"]
12
+ end
@@ -1,5 +1,5 @@
1
- require 'rails/generators'
2
- require 'rails/generators/migration'
1
+ require "rails/generators"
2
+ require "rails/generators/migration"
3
3
 
4
4
  # rails g payday:setup <invoice_name> <line_item_name>
5
5
  # Generates models for invoicing with Payday includes prepped
@@ -10,29 +10,29 @@ require 'rails/generators/migration'
10
10
  module Payday
11
11
  class SetupGenerator < Rails::Generators::Base
12
12
  include Rails::Generators::Migration
13
-
14
- source_root File.expand_path('../templates', __FILE__)
15
-
16
- class_option :invoice_name, :type => :string, :default => "Invoice"
17
- class_option :line_item_name, :type => :string, :default => "LineItem"
18
- class_option :skip_migration, :desc => "Does not create the migration file for tables", :type => :boolean
19
-
13
+
14
+ source_root File.expand_path("../templates", __FILE__)
15
+
16
+ class_option :invoice_name, type: :string, default: "Invoice"
17
+ class_option :line_item_name, type: :string, default: "LineItem"
18
+ class_option :skip_migration, desc: "Does not create the migration file for tables", type: :boolean
19
+
20
20
  def generate_invoice_model
21
21
  template "invoice.rb", "app/models/#{options.invoice_name.underscore}.rb"
22
22
  end
23
-
23
+
24
24
  def generate_line_item_model
25
25
  template "line_item.rb", "app/models/#{options.line_item_name.underscore}.rb"
26
26
  end
27
-
27
+
28
28
  def generate_migration
29
29
  unless options.skip_migration?
30
- migration_template 'migration.rb', "db/migrate/create_payday_tables.rb"
30
+ migration_template "migration.rb", "db/migrate/create_payday_tables.rb"
31
31
  end
32
32
  end
33
-
33
+
34
34
  private
35
-
35
+
36
36
  def self.next_migration_number(dirname)
37
37
  if ActiveRecord::Base.timestamped_migrations
38
38
  Time.now.utc.strftime("%Y%m%d%H%M%S")
@@ -41,4 +41,4 @@ module Payday
41
41
  end
42
42
  end
43
43
  end
44
- end
44
+ end
@@ -1,16 +1,16 @@
1
1
  # Not much to see here
2
- require 'date'
3
- require 'time'
4
- require 'bigdecimal'
5
- require 'prawn'
6
- require 'prawn-svg'
7
- require 'money'
2
+ require "date"
3
+ require "time"
4
+ require "bigdecimal"
5
+ require "prawn"
6
+ require "prawn-svg"
7
+ require "money"
8
8
 
9
- require_relative 'payday/version'
10
- require_relative 'payday/config'
11
- require_relative 'payday/i18n'
12
- require_relative 'payday/line_itemable'
13
- require_relative 'payday/line_item'
14
- require_relative 'payday/pdf_renderer'
15
- require_relative 'payday/invoiceable'
16
- require_relative 'payday/invoice'
9
+ require_relative "payday/version"
10
+ require_relative "payday/config"
11
+ require_relative "payday/i18n"
12
+ require_relative "payday/line_itemable"
13
+ require_relative "payday/line_item"
14
+ require_relative "payday/pdf_renderer"
15
+ require_relative "payday/invoiceable"
16
+ require_relative "payday/invoice"
@@ -1,5 +1,4 @@
1
1
  module Payday
2
-
3
2
  # Configuration for Payday. This is a singleton, so to set the company_name you would call
4
3
  # Payday::Config.default.company_name = "Awesome Corp".
5
4
  class Config
@@ -19,13 +18,13 @@ module Payday
19
18
  #
20
19
  # Primarily intended for use in our tests.
21
20
  def reset
22
- # TODO: Move into specs and make minimal configuration required (company name / details)
23
- self.invoice_logo = File.join(File.dirname(__FILE__), "..", "..", "spec", "assets", "default_logo.png")
24
- self.company_name = "Awesome Corp"
25
- self.company_details = "awesomecorp@commondream.net"
26
- self.date_format = "%B %e, %Y"
27
- self.currency = "USD"
28
- self.page_size = "LETTER"
21
+ # TODO: Move into specs and make minimal configuration required (company name / details)
22
+ self.invoice_logo = File.join(File.dirname(__FILE__), "..", "..", "spec", "assets", "default_logo.png")
23
+ self.company_name = "Awesome Corp"
24
+ self.company_details = "awesomecorp@commondream.net"
25
+ self.date_format = "%B %e, %Y"
26
+ self.currency = "USD"
27
+ self.page_size = "LETTER"
29
28
  end
30
29
 
31
30
  # Internal: Contruct a new config object.
@@ -1,11 +1,10 @@
1
1
  module Payday
2
-
3
2
  # Basically just an invoice. Stick a ton of line items in it, add some details, and then render it out!
4
3
  class Invoice
5
4
  include Payday::Invoiceable
6
5
 
7
6
  attr_accessor :invoice_number, :bill_to, :ship_to, :notes, :line_items, :shipping_rate, :shipping_description,
8
- :tax_rate, :tax_description, :due_at, :paid_at, :refunded_at, :currency, :invoice_details, :invoice_date
7
+ :tax_rate, :tax_description, :due_at, :paid_at, :refunded_at, :currency, :invoice_details, :invoice_date
9
8
 
10
9
  def initialize(options = {})
11
10
  self.invoice_number = options[:invoice_number] || nil
@@ -13,17 +13,16 @@
13
13
  # If the +due_at+, +paid_at+, and +refunded_at+ methods are available, {Payday::Invoiceable} will use them to show due dates,
14
14
  # paid dates, and refunded dates, as well as stamps showing if the invoice is paid or due.
15
15
  module Payday::Invoiceable
16
-
17
16
  # Who the invoice is being sent to.
18
17
  def bill_to
19
18
  "Goofy McGoofison\nYour Invoice Doesn't\nHave It's Own BillTo Method"
20
19
  end
21
-
20
+
22
21
  # Calculates the subtotal of this invoice by adding up all of the line items
23
22
  def subtotal
24
- line_items.inject(BigDecimal.new("0")) { |result, item| result += item.amount }
23
+ line_items.reduce(BigDecimal.new("0")) { |result, item| result += item.amount }
25
24
  end
26
-
25
+
27
26
  # The tax for this invoice, as a BigDecimal
28
27
  def tax
29
28
  if defined?(tax_rate)
@@ -34,7 +33,7 @@ module Payday::Invoiceable
34
33
  0
35
34
  end
36
35
  end
37
-
36
+
38
37
  # TODO Add a per weight unit shipping cost
39
38
  # Calculates the shipping
40
39
  def shipping
@@ -44,42 +43,41 @@ module Payday::Invoiceable
44
43
  0
45
44
  end
46
45
  end
47
-
46
+
48
47
  # Calculates the total for this invoice.
49
48
  def total
50
49
  subtotal + tax + shipping
51
50
  end
52
-
51
+
53
52
  def overdue?
54
53
  defined?(:due_at) && ((due_at.is_a?(Date) && due_at < Date.today) || (due_at.is_a?(Time) && due_at < Time.now)) && !paid_at
55
54
  end
56
-
55
+
57
56
  def refunded?
58
57
  defined?(:refunded_at) && !!refunded_at
59
58
  end
60
-
59
+
61
60
  def paid?
62
61
  defined?(:paid_at) && !!paid_at
63
62
  end
64
-
63
+
65
64
  # Renders this invoice to pdf as a string
66
65
  def render_pdf
67
66
  Payday::PdfRenderer.render(self)
68
67
  end
69
-
68
+
70
69
  # Renders this invoice to pdf
71
70
  def render_pdf_to_file(path)
72
71
  Payday::PdfRenderer.render_to_file(self, path)
73
72
  end
74
-
73
+
75
74
  # Iterates through the details on this invoiceable. The block given should accept
76
75
  # two parameters, the detail name and the actual detail value.
77
76
  def each_detail(&block)
78
77
  return if defined?(invoice_details).nil?
79
-
78
+
80
79
  invoice_details.each do |detail|
81
80
  block.call(detail[0], detail[1])
82
81
  end
83
82
  end
84
83
  end
85
-
@@ -6,9 +6,9 @@ module Payday
6
6
  # Otherwise, we'll do our best to convert the set values to a +BigDecimal+.
7
7
  class LineItem
8
8
  include LineItemable
9
-
9
+
10
10
  attr_accessor :description, :quantity, :display_quantity, :display_price, :price
11
-
11
+
12
12
  # Initializes a new LineItem
13
13
  def initialize(options = {})
14
14
  self.quantity = options[:quantity] || "1"
@@ -17,15 +17,15 @@ module Payday
17
17
  self.price = options[:price] || "0.00"
18
18
  self.description = options[:description] || ""
19
19
  end
20
-
20
+
21
21
  # Sets the quantity of this {LineItem}
22
22
  def quantity=(value)
23
23
  @quantity = BigDecimal.new(value.to_s)
24
24
  end
25
-
25
+
26
26
  # Sets the price for this {LineItem}
27
27
  def price=(value)
28
28
  @price = BigDecimal.new(value.to_s)
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -5,4 +5,4 @@ module Payday::LineItemable
5
5
  def amount
6
6
  price * quantity
7
7
  end
8
- end
8
+ end
@@ -8,6 +8,7 @@ de:
8
8
  bill_to: Rechnung an
9
9
  ship_to: Versenden an
10
10
  invoice_no: "Rechnungsnr.:"
11
+ invoice_date: "Rechnungsdatum:"
11
12
  due_date: "Fälligkeit:"
12
13
  paid_date: "Zahlungsdatum:"
13
14
  subtotal: "Zwischensumme:"
@@ -1,9 +1,7 @@
1
1
  module Payday
2
-
3
2
  # The PDF renderer. We use this internally in Payday to render pdfs, but really you should just need to call
4
3
  # {{Payday::Invoiceable#render_pdf}} to render pdfs yourself.
5
4
  class PdfRenderer
6
-
7
5
  # Renders the given invoice as a pdf on disk
8
6
  def self.render_to_file(invoice, path)
9
7
  pdf(invoice).render_file(path)
@@ -15,280 +13,306 @@ module Payday
15
13
  end
16
14
 
17
15
  private
18
- def self.pdf(invoice)
19
- pdf = Prawn::Document.new(:page_size => invoice_or_default(invoice, :page_size))
20
16
 
21
- # set up some default styling
22
- pdf.font_size(8)
17
+ def self.pdf(invoice)
18
+ pdf = Prawn::Document.new(page_size: invoice_or_default(invoice, :page_size))
23
19
 
24
- stamp(invoice, pdf)
25
- company_banner(invoice, pdf)
26
- bill_to_ship_to(invoice, pdf)
27
- invoice_details(invoice, pdf)
28
- line_items_table(invoice, pdf)
29
- totals_lines(invoice, pdf)
30
- notes(invoice, pdf)
20
+ # set up some default styling
21
+ pdf.font_size(8)
31
22
 
32
- page_numbers(pdf)
23
+ stamp(invoice, pdf)
24
+ company_banner(invoice, pdf)
25
+ bill_to_ship_to(invoice, pdf)
26
+ invoice_details(invoice, pdf)
27
+ line_items_table(invoice, pdf)
28
+ totals_lines(invoice, pdf)
29
+ notes(invoice, pdf)
33
30
 
34
- pdf
35
- end
31
+ page_numbers(pdf)
36
32
 
37
- def self.stamp(invoice, pdf)
38
- stamp = nil
39
- if invoice.refunded?
40
- stamp = I18n.t 'payday.status.refunded', :default => "REFUNDED"
41
- elsif invoice.paid?
42
- stamp = I18n.t 'payday.status.paid', :default => "PAID"
43
- elsif invoice.overdue?
44
- stamp = I18n.t 'payday.status.overdue', :default => "OVERDUE"
45
- end
33
+ pdf
34
+ end
46
35
 
47
- if stamp
48
- pdf.bounding_box([150, pdf.cursor - 50], :width => pdf.bounds.width - 300) do
49
- pdf.font("Helvetica-Bold") do
50
- pdf.fill_color "cc0000"
51
- pdf.text stamp, :align=> :center, :size => 25, :rotate => 15
52
- end
36
+ def self.stamp(invoice, pdf)
37
+ stamp = nil
38
+ if invoice.refunded?
39
+ stamp = I18n.t "payday.status.refunded", default: "REFUNDED"
40
+ elsif invoice.paid?
41
+ stamp = I18n.t "payday.status.paid", default: "PAID"
42
+ elsif invoice.overdue?
43
+ stamp = I18n.t "payday.status.overdue", default: "OVERDUE"
44
+ end
45
+
46
+ if stamp
47
+ pdf.bounding_box([150, pdf.cursor - 50], width: pdf.bounds.width - 300) do
48
+ pdf.font("Helvetica-Bold") do
49
+ pdf.fill_color "cc0000"
50
+ pdf.text stamp, align: :center, size: 25, rotate: 15
53
51
  end
54
52
  end
55
-
56
- pdf.fill_color "000000"
57
53
  end
58
54
 
59
- def self.company_banner(invoice, pdf)
60
- # render the logo
61
- image = invoice_or_default(invoice, :invoice_logo)
62
- height = nil
63
- width = nil
64
-
65
- # Handle images defined with a hash of options
66
- if image.is_a?(Hash)
67
- data = image
68
- image = data[:filename]
69
- width, height = data[:size].split("x").map(&:to_f)
70
- end
55
+ pdf.fill_color "000000"
56
+ end
71
57
 
72
- if File.extname(image) == ".svg"
73
- logo_info = pdf.svg(File.read(image), :at => pdf.bounds.top_left, :width => width, :height => height)
74
- logo_height = logo_info[:height]
75
- else
76
- logo_info = pdf.image(image, :at => pdf.bounds.top_left, :width => width, :height => height)
77
- logo_height = logo_info.scaled_height
78
- end
58
+ def self.company_banner(invoice, pdf)
59
+ # render the logo
60
+ image = invoice_or_default(invoice, :invoice_logo)
61
+ height = nil
62
+ width = nil
63
+
64
+ # Handle images defined with a hash of options
65
+ if image.is_a?(Hash)
66
+ data = image
67
+ image = data[:filename]
68
+ width, height = data[:size].split("x").map(&:to_f)
69
+ end
79
70
 
80
- # render the company details
81
- table_data = []
82
- table_data << [bold_cell(pdf, invoice_or_default(invoice, :company_name).strip, :size => 12)]
71
+ if File.extname(image) == ".svg"
72
+ logo_info = pdf.svg(File.read(image), at: pdf.bounds.top_left, width: width, height: height)
73
+ logo_height = logo_info[:height]
74
+ else
75
+ logo_info = pdf.image(image, at: pdf.bounds.top_left, width: width, height: height)
76
+ logo_height = logo_info.scaled_height
77
+ end
83
78
 
84
- invoice_or_default(invoice, :company_details).lines.each { |line| table_data << [line] }
79
+ # render the company details
80
+ table_data = []
81
+ table_data << [bold_cell(pdf, invoice_or_default(invoice, :company_name).strip, size: 12)]
85
82
 
86
- table = pdf.make_table(table_data, :cell_style => { :borders => [], :padding => 0 })
87
- pdf.bounding_box([pdf.bounds.width - table.width, pdf.bounds.top], :width => table.width, :height => table.height + 5) do
88
- table.draw
89
- end
83
+ invoice_or_default(invoice, :company_details).lines.each { |line| table_data << [line] }
90
84
 
91
- pdf.move_cursor_to(pdf.bounds.top - logo_height - 20)
85
+ table = pdf.make_table(table_data, cell_style: { borders: [], padding: 0 })
86
+ pdf.bounding_box([pdf.bounds.width - table.width, pdf.bounds.top], width: table.width, height: table.height + 5) do
87
+ table.draw
92
88
  end
93
89
 
94
- def self.bill_to_ship_to(invoice, pdf)
95
- bill_to_cell_style = { :borders => [], :padding => [2, 0]}
96
- bill_to_ship_to_bottom = 0
97
-
98
- # render bill to
99
- pdf.float do
100
- table = pdf.table([[bold_cell(pdf, I18n.t('payday.invoice.bill_to', :default => "Bill To"))],
101
- [invoice.bill_to]], :column_widths => [200], :cell_style => bill_to_cell_style)
102
- bill_to_ship_to_bottom = pdf.cursor
103
- end
104
-
105
- # render ship to
106
- if defined?(invoice.ship_to) && !invoice.ship_to.nil?
107
- table = pdf.make_table([[bold_cell(pdf, I18n.t('payday.invoice.ship_to', :default => "Ship To"))],
108
- [invoice.ship_to]], :column_widths => [200], :cell_style => bill_to_cell_style)
90
+ pdf.move_cursor_to(pdf.bounds.top - logo_height - 20)
91
+ end
109
92
 
110
- pdf.bounding_box([pdf.bounds.width - table.width, pdf.cursor], :width => table.width, :height => table.height + 2) do
111
- table.draw
112
- end
113
- end
93
+ def self.bill_to_ship_to(invoice, pdf)
94
+ bill_to_cell_style = { borders: [], padding: [2, 0] }
95
+ bill_to_ship_to_bottom = 0
114
96
 
115
- # make sure we start at the lower of the bill_to or ship_to details
116
- bill_to_ship_to_bottom = pdf.cursor if pdf.cursor < bill_to_ship_to_bottom
117
- pdf.move_cursor_to(bill_to_ship_to_bottom - 20)
97
+ # render bill to
98
+ pdf.float do
99
+ table = pdf.table([[bold_cell(pdf, I18n.t("payday.invoice.bill_to", default: "Bill To"))],
100
+ [invoice.bill_to]], column_widths: [200], cell_style: bill_to_cell_style)
101
+ bill_to_ship_to_bottom = pdf.cursor
118
102
  end
119
103
 
120
- def self.invoice_details(invoice, pdf)
121
- # invoice details
122
- table_data = []
104
+ # render ship to
105
+ if defined?(invoice.ship_to) && !invoice.ship_to.nil?
106
+ table = pdf.make_table([[bold_cell(pdf, I18n.t("payday.invoice.ship_to", default: "Ship To"))],
107
+ [invoice.ship_to]], column_widths: [200], cell_style: bill_to_cell_style)
123
108
 
124
- # invoice number
125
- if defined?(invoice.invoice_number) && invoice.invoice_number
126
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.invoice_no', :default => "Invoice #:")),
127
- bold_cell(pdf, invoice.invoice_number.to_s, :align => :right)]
128
- end
129
-
130
- # invoice date
131
- if defined?(invoice.invoice_date) && invoice.invoice_date
132
- if invoice.invoice_date.is_a?(Date) || invoice.invoice_date.is_a?(Time)
133
- invoice_date = invoice.invoice_date.strftime(Payday::Config.default.date_format)
134
- else
135
- invoice_date = invoice.invoice_date.to_s
136
- end
137
-
138
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.invoice_date', :default => "Invoice Date:")),
139
- bold_cell(pdf, invoice_date, :align => :right)]
109
+ pdf.bounding_box([pdf.bounds.width - table.width, pdf.cursor], width: table.width, height: table.height + 2) do
110
+ table.draw
140
111
  end
112
+ end
141
113
 
142
- # Due on
143
- if defined?(invoice.due_at) && invoice.due_at
144
- if invoice.due_at.is_a?(Date) || invoice.due_at.is_a?(Time)
145
- due_date = invoice.due_at.strftime(Payday::Config.default.date_format)
146
- else
147
- due_date = invoice.due_at.to_s
148
- end
114
+ # make sure we start at the lower of the bill_to or ship_to details
115
+ bill_to_ship_to_bottom = pdf.cursor if pdf.cursor < bill_to_ship_to_bottom
116
+ pdf.move_cursor_to(bill_to_ship_to_bottom - 20)
117
+ end
149
118
 
150
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.due_date', :default => "Due Date:")),
151
- bold_cell(pdf, due_date, :align => :right)]
152
- end
119
+ def self.invoice_details(invoice, pdf)
120
+ # invoice details
121
+ table_data = []
153
122
 
154
- # Paid on
155
- if defined?(invoice.paid_at) && invoice.paid_at
156
- if invoice.paid_at.is_a?(Date) || invoice.due_at.is_a?(Time)
157
- paid_date = invoice.paid_at.strftime(Payday::Config.default.date_format)
158
- else
159
- paid_date = invoice.paid_at.to_s
160
- end
123
+ # invoice number
124
+ if defined?(invoice.invoice_number) && invoice.invoice_number
125
+ table_data << [bold_cell(pdf, I18n.t("payday.invoice.invoice_no", default: "Invoice #:")),
126
+ bold_cell(pdf, invoice.invoice_number.to_s, align: :right)]
127
+ end
161
128
 
162
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.paid_date', :default => "Paid Date:")),
163
- bold_cell(pdf, paid_date, :align => :right)]
129
+ # invoice date
130
+ if defined?(invoice.invoice_date) && invoice.invoice_date
131
+ if invoice.invoice_date.is_a?(Date) || invoice.invoice_date.is_a?(Time)
132
+ invoice_date = invoice.invoice_date.strftime(Payday::Config.default.date_format)
133
+ else
134
+ invoice_date = invoice.invoice_date.to_s
164
135
  end
165
136
 
166
- # Refunded on
167
- if defined?(invoice.refunded_at) && invoice.refunded_at
168
- if invoice.refunded_at.is_a?(Date) || invoice.due_at.is_a?(Time)
169
- refunded_date = invoice.refunded_at.strftime(Payday::Config.default.date_format)
170
- else
171
- refunded_date = invoice.refunded_at.to_s
172
- end
137
+ table_data << [bold_cell(pdf, I18n.t("payday.invoice.invoice_date", default: "Invoice Date:")),
138
+ bold_cell(pdf, invoice_date, align: :right)]
139
+ end
173
140
 
174
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.refunded_date', :default => "Refunded Date:")),
175
- bold_cell(pdf, refunded_date, :align => :right)]
141
+ # Due on
142
+ if defined?(invoice.due_at) && invoice.due_at
143
+ if invoice.due_at.is_a?(Date) || invoice.due_at.is_a?(Time)
144
+ due_date = invoice.due_at.strftime(Payday::Config.default.date_format)
145
+ else
146
+ due_date = invoice.due_at.to_s
176
147
  end
177
148
 
178
- # loop through invoice_details and include them
179
- invoice.each_detail do |key, value|
180
- table_data << [bold_cell(pdf, key),
181
- bold_cell(pdf, value, :align => :right)]
182
- end
149
+ table_data << [bold_cell(pdf, I18n.t("payday.invoice.due_date", default: "Due Date:")),
150
+ bold_cell(pdf, due_date, align: :right)]
151
+ end
183
152
 
184
- if table_data.length > 0
185
- pdf.table(table_data, :cell_style => { :borders => [], :padding => [1, 10, 1, 1] })
153
+ # Paid on
154
+ if defined?(invoice.paid_at) && invoice.paid_at
155
+ if invoice.paid_at.is_a?(Date) || invoice.paid_at.is_a?(Time)
156
+ paid_date = invoice.paid_at.strftime(Payday::Config.default.date_format)
157
+ else
158
+ paid_date = invoice.paid_at.to_s
186
159
  end
160
+
161
+ table_data << [bold_cell(pdf, I18n.t("payday.invoice.paid_date", default: "Paid Date:")),
162
+ bold_cell(pdf, paid_date, align: :right)]
187
163
  end
188
164
 
189
- def self.line_items_table(invoice, pdf)
190
- table_data = []
191
- table_data << [bold_cell(pdf, I18n.t('payday.line_item.description', :default => "Description"), :borders => []),
192
- bold_cell(pdf, I18n.t('payday.line_item.unit_price', :default => "Unit Price"), :align => :center, :borders => []),
193
- bold_cell(pdf, I18n.t('payday.line_item.quantity', :default => "Quantity"), :align => :center, :borders => []),
194
- bold_cell(pdf, I18n.t('payday.line_item.amount', :default => "Amount"), :align => :center, :borders => [])]
195
- invoice.line_items.each do |line|
196
- table_data << [line.description,
197
- (line.display_price || number_to_currency(line.price, invoice)),
198
- (line.display_quantity || BigDecimal.new(line.quantity.to_s).to_s("F")),
199
- number_to_currency(line.amount, invoice)]
165
+ # Refunded on
166
+ if defined?(invoice.refunded_at) && invoice.refunded_at
167
+ if invoice.refunded_at.is_a?(Date) || invoice.refunded_at.is_a?(Time)
168
+ refunded_date = invoice.refunded_at.strftime(Payday::Config.default.date_format)
169
+ else
170
+ refunded_date = invoice.refunded_at.to_s
200
171
  end
201
172
 
202
- pdf.move_cursor_to(pdf.cursor - 20)
203
- pdf.table(table_data, :width => pdf.bounds.width, :header => true,
204
- :cell_style => {:border_width => 0.5, :border_color => "cccccc", :padding => [5, 10]},
205
- :row_colors => ["dfdfdf", "ffffff"]) do
206
- # left align the number columns
207
- columns(1..3).rows(1..row_length - 1).style(:align => :right)
173
+ table_data << [bold_cell(pdf, I18n.t("payday.invoice.refunded_date", default: "Refunded Date:")),
174
+ bold_cell(pdf, refunded_date, align: :right)]
175
+ end
208
176
 
209
- # set the column widths correctly
210
- natural = natural_column_widths
211
- natural[0] = width - natural[1] - natural[2] - natural[3]
177
+ # loop through invoice_details and include them
178
+ invoice.each_detail do |key, value|
179
+ table_data << [bold_cell(pdf, key),
180
+ bold_cell(pdf, value, align: :right)]
181
+ end
212
182
 
213
- column_widths = natural
214
- end
183
+ if table_data.length > 0
184
+ pdf.table(table_data, cell_style: { borders: [], padding: [1, 10, 1, 1] })
215
185
  end
186
+ end
216
187
 
217
- def self.totals_lines(invoice, pdf)
218
- table_data = []
219
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.subtotal', :default => "Subtotal:")),
220
- cell(pdf, number_to_currency(invoice.subtotal, invoice), :align => :right)]
221
- if invoice.tax_rate > 0
222
- table_data << [bold_cell(pdf,
223
- invoice.tax_description.nil? ? I18n.t('payday.invoice.tax', :default => "Tax:") : invoice.tax_description),
224
- cell(pdf, number_to_currency(invoice.tax, invoice), :align => :right)]
225
- end
226
- if invoice.shipping_rate > 0
227
- table_data << [bold_cell(pdf,
228
- invoice.shipping_description.nil? ? I18n.t('payday.invoice.shipping', :default => "Shipping:") : invoice.shipping_description),
229
- cell(pdf, number_to_currency(invoice.shipping, invoice), :align => :right)]
230
- end
231
- table_data << [bold_cell(pdf, I18n.t('payday.invoice.total', :default => "Total:"), :size => 12),
232
- cell(pdf, number_to_currency(invoice.total, invoice), :size => 12, :align => :right)]
233
- table = pdf.make_table(table_data, :cell_style => { :borders => [] })
234
- pdf.bounding_box([pdf.bounds.width - table.width, pdf.cursor], :width => table.width, :height => table.height + 2) do
235
- table.draw
236
- end
188
+ def self.line_items_table(invoice, pdf)
189
+ table_data = []
190
+ table_data << [bold_cell(pdf, I18n.t("payday.line_item.description", default: "Description"), borders: []),
191
+ bold_cell(pdf, I18n.t("payday.line_item.unit_price", default: "Unit Price"), align: :center, borders: []),
192
+ bold_cell(pdf, I18n.t("payday.line_item.quantity", default: "Quantity"), align: :center, borders: []),
193
+ bold_cell(pdf, I18n.t("payday.line_item.amount", default: "Amount"), align: :center, borders: [])]
194
+ invoice.line_items.each do |line|
195
+ table_data << [line.description,
196
+ (line.display_price || number_to_currency(line.price, invoice)),
197
+ (line.display_quantity || BigDecimal.new(line.quantity.to_s).to_s("F")),
198
+ number_to_currency(line.amount, invoice)]
237
199
  end
238
200
 
239
- def self.notes(invoice, pdf)
240
- if defined?(invoice.notes) && invoice.notes
241
- pdf.move_cursor_to(pdf.cursor - 30)
242
- pdf.font("Helvetica-Bold") do
243
- pdf.text(I18n.t('payday.invoice.notes', :default => "Notes"))
244
- end
245
- pdf.line_width = 0.5
246
- pdf.stroke_color = "cccccc"
247
- pdf.stroke_line([0, pdf.cursor - 3, pdf.bounds.width, pdf.cursor - 3])
248
- pdf.move_cursor_to(pdf.cursor - 10)
249
- pdf.text(invoice.notes.to_s)
250
- end
201
+ pdf.move_cursor_to(pdf.cursor - 20)
202
+ pdf.table(table_data, width: pdf.bounds.width, header: true,
203
+ cell_style: { border_width: 0.5, border_color: "cccccc",
204
+ padding: [5, 10] },
205
+ row_colors: %w(dfdfdf ffffff)) do
206
+
207
+ # left align the number columns
208
+ columns(1..3).rows(1..row_length - 1).style(align: :right)
209
+
210
+ # set the column widths correctly
211
+ natural = natural_column_widths
212
+ natural[0] = width - natural[1] - natural[2] - natural[3]
213
+
214
+ column_widths = natural
251
215
  end
216
+ end
217
+
218
+ def self.totals_lines(invoice, pdf)
219
+ table_data = []
220
+ table_data << [
221
+ bold_cell(pdf, I18n.t("payday.invoice.subtotal", default: "Subtotal:")),
222
+ cell(pdf, number_to_currency(invoice.subtotal, invoice), align: :right)
223
+ ]
252
224
 
253
- def self.page_numbers(pdf)
254
- if pdf.page_count > 1
255
- pdf.number_pages("<page> / <total>", :at => [pdf.bounds.right - 18, -15])
225
+ if invoice.tax_rate > 0
226
+ if invoice.tax_description.nil?
227
+ tax_description = I18n.t("payday.invoice.tax", default: "Tax:")
228
+ else
229
+ tax_description = invoice.tax_description
256
230
  end
257
- end
258
231
 
259
- def self.invoice_or_default(invoice, property)
260
- if invoice.respond_to?(property) && invoice.send(property)
261
- invoice.send(property)
232
+ table_data << [
233
+ bold_cell(pdf, tax_description),
234
+ cell(pdf, number_to_currency(invoice.tax, invoice), align: :right)
235
+ ]
236
+ end
237
+ if invoice.shipping_rate > 0
238
+ if invoice.shipping_description.nil?
239
+ shipping_description =
240
+ I18n.t("payday.invoice.shipping", default: "Shipping:")
262
241
  else
263
- Payday::Config.default.send(property)
242
+ shipping_description = invoice.shipping_description
264
243
  end
244
+
245
+ table_data << [
246
+ bold_cell(pdf, shipping_description),
247
+ cell(pdf, number_to_currency(invoice.shipping, invoice),
248
+ align: :right)
249
+ ]
250
+ end
251
+ table_data << [
252
+ bold_cell(pdf, I18n.t("payday.invoice.total", default: "Total:"),
253
+ size: 12),
254
+ cell(pdf, number_to_currency(invoice.total, invoice),
255
+ size: 12, align: :right)
256
+ ]
257
+ table = pdf.make_table(table_data, cell_style: { borders: [] })
258
+ pdf.bounding_box([pdf.bounds.width - table.width, pdf.cursor],
259
+ width: table.width, height: table.height + 2) do
260
+
261
+ table.draw
265
262
  end
263
+ end
266
264
 
267
- def self.cell(pdf, text, options = {})
268
- Prawn::Table::Cell::Text.make(pdf, text, options)
265
+ def self.notes(invoice, pdf)
266
+ if defined?(invoice.notes) && invoice.notes
267
+ pdf.move_cursor_to(pdf.cursor - 30)
268
+ pdf.font("Helvetica-Bold") do
269
+ pdf.text(I18n.t("payday.invoice.notes", default: "Notes"))
270
+ end
271
+ pdf.line_width = 0.5
272
+ pdf.stroke_color = "cccccc"
273
+ pdf.stroke_line([0, pdf.cursor - 3, pdf.bounds.width, pdf.cursor - 3])
274
+ pdf.move_cursor_to(pdf.cursor - 10)
275
+ pdf.text(invoice.notes.to_s)
269
276
  end
277
+ end
270
278
 
271
- def self.bold_cell(pdf, text, options = {})
272
- cell(pdf, "<b>#{text}</b>", options.merge(:inline_format => true))
279
+ def self.page_numbers(pdf)
280
+ if pdf.page_count > 1
281
+ pdf.number_pages("<page> / <total>", at: [pdf.bounds.right - 18, -15])
273
282
  end
283
+ end
274
284
 
275
- # Converts this number to a formatted currency string
276
- def self.number_to_currency(number, invoice)
277
- currency = Money::Currency.wrap(invoice_or_default(invoice, :currency))
278
- number = number * currency.subunit_to_unit
279
- number = number.round unless Money.infinite_precision
280
- Money.new(number, currency).format
285
+ def self.invoice_or_default(invoice, property)
286
+ if invoice.respond_to?(property) && invoice.send(property)
287
+ invoice.send(property)
288
+ else
289
+ Payday::Config.default.send(property)
281
290
  end
291
+ end
282
292
 
283
- def self.max_cell_width(cell_proxy)
284
- max = 0
285
- cell_proxy.each do |cell|
286
- if cell.natural_content_width > max
287
- max = cell.natural_content_width
288
- end
289
- end
293
+ def self.cell(pdf, text, options = {})
294
+ Prawn::Table::Cell::Text.make(pdf, text, options)
295
+ end
296
+
297
+ def self.bold_cell(pdf, text, options = {})
298
+ cell(pdf, "<b>#{text}</b>", options.merge(inline_format: true))
299
+ end
290
300
 
291
- max
301
+ # Converts this number to a formatted currency string
302
+ def self.number_to_currency(number, invoice)
303
+ currency = Money::Currency.wrap(invoice_or_default(invoice, :currency))
304
+ number *= currency.subunit_to_unit
305
+ number = number.round unless Money.infinite_precision
306
+ Money.new(number, currency).format
307
+ end
308
+
309
+ def self.max_cell_width(cell_proxy)
310
+ max = 0
311
+ cell_proxy.each do |cell|
312
+ max = cell.natural_content_width if cell.natural_content_width > max
292
313
  end
314
+
315
+ max
316
+ end
293
317
  end
294
318
  end