payday 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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