webtranslateit-payday 2.0.0 → 2.1.1

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
  SHA256:
3
- metadata.gz: c69e90db47eb429202583e59002641017e200efa98a05989a8112db2504ca8d6
4
- data.tar.gz: 0e1a0a649e12c88225f5eafd95bc7b2eb2f1a1b3825570ca54611ea072d16a6a
3
+ metadata.gz: e997f24c5936a24f8deb333262cdfb74ecf989ddd229052797211579748a8f8c
4
+ data.tar.gz: af5120a7dd9edd4a7cf8e980d5090f2c20a2d1e0c32d654aa711c93b777cc429
5
5
  SHA512:
6
- metadata.gz: 3bfaddfd9cbd922672a519e1309e723a8abfa5e64d035e1d3e355c9437ce93d0734fdfbfb7b624b1389f2ff66dc65685327a9cd802826055468b6353351df606
7
- data.tar.gz: beac41f39e7cc6013e6eb7f94057e55042daad14c73a17b33a2e99bbcbc8b23d0b63e4c67618c5338298131e02c3f1614349d89983a42805ac693d76a0df1625
6
+ metadata.gz: 73f336ccbb26a4e1ab7b98ca3f95cd407e5730d7508884c361049e1ad1120b6a09f02609f44f5edb4e492d5dff0563c3021c16fc72e67756926c50463308875e
7
+ data.tar.gz: ab853437c9e8d4bcdb647bde8535e0d0a5e18a9e93e5d132be4cebaccec844a5e649915123ac4216d50f832c79604905a3d7eb755b5e5dbae59cfa957d749126
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.1.1 (2026-11-08)
4
+
5
+ * An invoice that defines `date_format` now has its dates formatted with it, the way it could already override `currency`, `invoice_logo`, `page_size`, `company_name` and `company_details`. Every one of those is read through the new `Config#value_for(invoice, property)` (#319, #321). `Payday::Invoice` has no `date_format`, so its output is unchanged.
6
+ * Internal refactoring, no behaviour change: `Invoice#initialize` assigns its options from one list (#314); the invoice rate setters and the `LineItem` setters each share one decimal conversion (#315, #316); `Invoiceable#tax`, `#shipping` and `#retention` are one-liners (#315); `overdue?` reads through `Invoiceable.past?` (#317); `each_detail` is tidied (#318); and two doc comments no longer need RuboCop line-length directives (#320).
7
+ * The code satisfies RuboCop 1.90's `Style/DirectiveScope` cop, the linter runs on Ruby 4.0, and guard and pry are gone from the development setup.
8
+
9
+ ## 2.1.0 (2026-08-27)
10
+
11
+ * Add `Payday::Appendix`, for compiling pages of your own onto the end of an invoice. `render_pdf`, `render_pdf_to_file`, `PdfRenderer.render` and `PdfRenderer.render_to_file` all take an `appendix:` keyword; every signature stays backward compatible and an invoice rendered without one is byte-for-byte what it was.
12
+
13
+ The appendix carries Typst `source`, plus `inputs` that reach it as sys_inputs JSON and `dependencies` it can resolve by name. The source is concatenated onto Payday's template rather than compiled separately, so the appended pages keep the invoice's page setup and the numbering footer counts them: a one-page invoice with an appendix numbers "1 / 2" and "2 / 2". Merging a second PDF in could do neither.
14
+
15
+ Data belongs in `inputs`, where Typst treats it as literal text. Interpolating invoice data into `source` would give it the run of the document, which is the same rule the invoice template already follows.
16
+
17
+ An appendix that reuses a name the invoice has taken — the `invoice` input, or the logo and QR code files — raises `ArgumentError` instead of replacing it.
18
+
3
19
  ## 2.0.0 (2026-08-26)
4
20
 
5
21
  **Breaking:** Payday now renders with [Typst](https://typst.app) instead of Prawn. The `prawn`, `prawn-table` and `prawn-svg` dependencies are gone, replaced by the single Apache-2.0 licensed `typst` gem, which ships precompiled native builds for macOS and Linux on both x86_64 and arm64.
data/README.md CHANGED
@@ -115,6 +115,35 @@ end
115
115
 
116
116
  Be sure to restart your server after you edit the mime_types initializer. The updated setting won't take effect until you do.
117
117
 
118
+ Appending your own pages
119
+ ===
120
+ Pass a `Payday::Appendix` to add pages of your own to the end of an invoice — a per-item breakdown, a delivery note, terms and conditions:
121
+
122
+ ``` ruby
123
+ appendix = Payday::Appendix.new(
124
+ source: File.read('appendix.typ'),
125
+ inputs: {'shipments' => shipments.to_json},
126
+ dependencies: {'chart.svg' => File.binread('chart.svg')}
127
+ )
128
+
129
+ invoice.render_pdf(appendix: appendix)
130
+ ```
131
+
132
+ `source` is [Typst](https://typst.app) markup appended to Payday's own template, so it is compiled as part of the invoice rather than as a second PDF you would then have to merge in. Two things follow from that: your pages inherit the invoice's page setup and margins, and the page counter runs across the whole document, so the numbering footer counts your pages too. A one-page invoice with one appended page comes out numbered "1 / 2" and "2 / 2".
133
+
134
+ `inputs` reach the template as [sys_inputs](https://typst.app/docs/reference/foundations/sys/), read with `json(bytes(sys.inputs.shipments))`. `dependencies` are files the source can reach by name, with `image("chart.svg")` and the like. Reusing a name the invoice has already taken — the `invoice` input, or the logo and QR code files — raises an `ArgumentError` rather than quietly replacing it.
135
+
136
+ **Pass your data through `inputs`, never by interpolating it into `source`.** Typst treats a string arriving through `sys.inputs` as literal text, which is what stops a customer-supplied field from affecting the layout. `source` is code: interpolating invoice data into it hands anyone who can set a field on an invoice a way to write Typst.
137
+
138
+ An appendix that reads its data and prints a heading:
139
+
140
+ ``` typst
141
+ #let a = json(bytes(sys.inputs.shipments))
142
+
143
+ #pagebreak()
144
+ #text(size: 16pt, weight: "bold")[#a.title]
145
+ ```
146
+
118
147
  I18n
119
148
  ===
120
149
  Payday uses the i18n gem to provide support for custom labels and internationalized applications. You can change the default labels by adding a YAML file in the `config/locales` directory of your Rails app. Here are the default labels you can customize:
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Payday
4
+
5
+ # Extra pages compiled onto the end of an invoice.
6
+ #
7
+ # appendix = Payday::Appendix.new(
8
+ # source: File.read('appendix.typ'),
9
+ # inputs: {'shipments' => shipments.to_json},
10
+ # dependencies: {'chart.svg' => File.binread('chart.svg')}
11
+ # )
12
+ # invoice.render_pdf(appendix: appendix)
13
+ #
14
+ # +source+ is Typst markup appended to Payday's own template, so it is compiled as part of
15
+ # the invoice rather than as a second document that would then have to be merged in. Two
16
+ # things follow from that. The template's +#set page+ rules stay in force, so the appended
17
+ # pages keep the invoice's margins; and the page counter runs across the whole document, so
18
+ # the numbering footer counts the appended pages. A one-page invoice with one appended page
19
+ # numbers "1 / 2", and a three-page invoice continues into "4 / 4".
20
+ #
21
+ # That is also why the source is concatenated rather than +#include+d: an included file is
22
+ # its own module, and the page rules set inside the template would stop at its edge.
23
+ #
24
+ # **Pass your data through +inputs+, never through +source+.** Inputs reach the template as
25
+ # sys_inputs JSON, where Typst treats every string as literal text, which is what stops a
26
+ # customer-supplied field from affecting the layout. Source is code. Interpolating invoice
27
+ # data into it gives that data back the run of the document, and hands anyone who can set a
28
+ # field on an invoice a way to write Typst.
29
+ #
30
+ # +dependencies+ are files the source can reach by name -- +image("chart.svg")+ and the
31
+ # like. Keys are file names, values are the bytes.
32
+ Appendix = Data.define(:source, :inputs, :dependencies) do
33
+
34
+ # Accepts an Appendix, a Hash of the same attributes, or nil.
35
+ def self.wrap(value)
36
+ return value if value.nil? || value.is_a?(Appendix)
37
+
38
+ new(**value)
39
+ end
40
+
41
+ def initialize(source:, inputs: {}, dependencies: {})
42
+ super(source: source, inputs: inputs.transform_keys(&:to_s), dependencies: dependencies.transform_keys(&:to_s))
43
+ end
44
+
45
+ end
46
+
47
+ end
data/lib/payday/config.rb CHANGED
@@ -18,6 +18,13 @@ module Payday
18
18
  @default ||= new
19
19
  end
20
20
 
21
+ # The invoice's own value for +property+ when it defines one and it is set, otherwise this
22
+ # config's. Every setting an invoice can override is read through here.
23
+ def value_for(invoice, property)
24
+ value = invoice.public_send(property) if invoice.respond_to?(property)
25
+ value || public_send(property)
26
+ end
27
+
21
28
  # Internal: Resets a config object back to its default settings.
22
29
  #
23
30
  # Primarily intended for use in our tests.
@@ -13,49 +13,30 @@ module Payday
13
13
 
14
14
  attr_reader :tax_rate, :shipping_rate, :retention_rate
15
15
 
16
- # rubocop:todo Metrics/PerceivedComplexity
17
- # rubocop:todo Metrics/MethodLength
18
- # rubocop:todo Metrics/AbcSize
19
- def initialize(options = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
20
- self.invoice_number = options[:invoice_number] || nil
21
- self.bill_to = options[:bill_to] || nil
22
- self.ship_to = options[:ship_to] || nil
23
- self.notes = options[:notes] || nil
16
+ # Options assigned as given; a missing one is nil, which the rate setters turn into 0.
17
+ OPTIONS = %i[invoice_number bill_to ship_to notes shipping_rate shipping_description tax_rate
18
+ tax_description retention_rate retention_description due_at paid_at refunded_at
19
+ currency invoice_date qr_code].freeze
20
+
21
+ def initialize(options = {})
22
+ OPTIONS.each { |name| public_send(:"#{name}=", options[name]) }
24
23
  self.line_items = options[:line_items] || []
25
- self.shipping_rate = options[:shipping_rate] || nil
26
- self.shipping_description = options[:shipping_description] || nil
27
- self.tax_rate = options[:tax_rate] || nil
28
- self.tax_description = options[:tax_description] || nil
29
- self.retention_rate = options[:retention_rate] || nil
30
- self.retention_description = options[:retention_description] || nil
31
- self.due_at = options[:due_at] || nil
32
- self.paid_at = options[:paid_at] || nil
33
- self.refunded_at = options[:refunded_at] || nil
34
- self.currency = options[:currency] || nil
35
24
  self.invoice_details = options[:invoice_details] || []
36
- self.invoice_date = options[:invoice_date] || nil
37
- self.qr_code = options[:qr_code] || nil
38
25
  end
39
- # rubocop:enable Metrics/AbcSize
40
- # rubocop:enable Metrics/MethodLength
41
- # rubocop:enable Metrics/PerceivedComplexity
42
26
 
43
27
  # The tax rate that we're applying, as a BigDecimal
44
28
  def tax_rate=(value)
45
- value = 0 if value.to_s.blank?
46
- @tax_rate = BigDecimal(value.to_s)
29
+ @tax_rate = to_rate(value)
47
30
  end
48
31
 
49
32
  # Shipping rate
50
33
  def shipping_rate=(value)
51
- value = 0 if value.to_s.blank?
52
- @shipping_rate = BigDecimal(value.to_s)
34
+ @shipping_rate = to_rate(value)
53
35
  end
54
36
 
55
37
  # Retention rate (e.g. IRPF). Applied as a percentage of the subtotal and deducted from the total.
56
38
  def retention_rate=(value)
57
- value = 0 if value.to_s.blank?
58
- @retention_rate = BigDecimal(value.to_s)
39
+ @retention_rate = to_rate(value)
59
40
  end
60
41
 
61
42
  # Adds a line item
@@ -63,6 +44,13 @@ module Payday
63
44
  line_items << Payday::LineItem.new(options)
64
45
  end
65
46
 
47
+ private
48
+
49
+ # A blank rate (nil, "", " ") is 0.
50
+ def to_rate(value)
51
+ BigDecimal(value.to_s.presence || 0)
52
+ end
53
+
66
54
  end
67
55
 
68
56
  end
@@ -144,7 +144,7 @@ module Payday
144
144
  def date(value)
145
145
  return value.to_s unless value.is_a?(Date) || value.is_a?(Time)
146
146
 
147
- value.strftime(Payday::Config.default.date_format)
147
+ value.strftime(setting(:date_format))
148
148
  end
149
149
 
150
150
  def t(key, default)
@@ -152,9 +152,7 @@ module Payday
152
152
  end
153
153
 
154
154
  def setting(property)
155
- return @invoice.send(property) if @invoice.respond_to?(property) && @invoice.send(property)
156
-
157
- Payday::Config.default.send(property)
155
+ Payday::Config.default.value_for(@invoice, property)
158
156
  end
159
157
 
160
158
  end
@@ -12,10 +12,8 @@
12
12
  # when generating an invoice. We include a simple tax method that calculates tax, but it's probably wiser
13
13
  # to override this in your class (our calculated tax won't be stored to a database by default, for example).
14
14
  #
15
- # rubocop:todo Layout/LineLength
16
- # If the +due_at+, +paid_at+, and +refunded_at+ methods are available, {Payday::Invoiceable} will use them to show due dates,
17
- # rubocop:enable Layout/LineLength
18
- # paid dates, and refunded dates, as well as stamps showing if the invoice is paid or due.
15
+ # If the +due_at+, +paid_at+, and +refunded_at+ methods are available, {Payday::Invoiceable} will use them
16
+ # to show due dates, paid dates, and refunded dates, as well as stamps showing if the invoice is paid or due.
19
17
  module Payday
20
18
 
21
19
  module Invoiceable
@@ -32,31 +30,19 @@ module Payday
32
30
 
33
31
  # The tax for this invoice, as a BigDecimal
34
32
  def tax
35
- if defined?(tax_rate)
36
- subtotal * tax_rate / 100
37
- else
38
- 0
39
- end
33
+ defined?(tax_rate) ? subtotal * tax_rate / 100 : 0
40
34
  end
41
35
 
42
36
  # TODO: Add a per weight unit shipping cost
43
37
  # Calculates the shipping
44
38
  def shipping
45
- if defined?(shipping_rate)
46
- shipping_rate
47
- else
48
- 0
49
- end
39
+ defined?(shipping_rate) ? shipping_rate : 0
50
40
  end
51
41
 
52
42
  # Calculates the retention (e.g. IRPF) as a percentage of the subtotal.
53
43
  # This is a post-tax deduction subtracted from the total.
54
44
  def retention
55
- if defined?(retention_rate)
56
- subtotal * retention_rate / 100
57
- else
58
- 0
59
- end
45
+ defined?(retention_rate) ? subtotal * retention_rate / 100 : 0
60
46
  end
61
47
 
62
48
  # Calculates the total for this invoice.
@@ -65,9 +51,17 @@ module Payday
65
51
  end
66
52
 
67
53
  def overdue?
68
- # rubocop:todo Layout/LineLength
69
- defined?(due_at) && ((due_at.is_a?(Date) && due_at < Date.today) || (due_at.is_a?(Time) && due_at < Time.now)) && !paid_at
70
- # rubocop:enable Layout/LineLength
54
+ defined?(due_at) && Invoiceable.past?(due_at) && !paid_at
55
+ end
56
+
57
+ # Whether a Date is before today or a Time before now. A module function rather than a
58
+ # private method, so it does not land in the classes that include Invoiceable.
59
+ def self.past?(moment)
60
+ case moment
61
+ when Date then moment < Date.today
62
+ when Time then moment < Time.now
63
+ else false
64
+ end
71
65
  end
72
66
 
73
67
  def refunded?
@@ -78,24 +72,23 @@ module Payday
78
72
  defined?(paid_at) && !!paid_at
79
73
  end
80
74
 
81
- # Renders this invoice to pdf as a string
82
- def render_pdf
83
- Payday::PdfRenderer.render(self)
75
+ # Renders this invoice to pdf as a string. Pass a Payday::Appendix to compile pages of
76
+ # your own onto the end of it.
77
+ def render_pdf(appendix: nil)
78
+ Payday::PdfRenderer.render(self, appendix: appendix)
84
79
  end
85
80
 
86
81
  # Renders this invoice to pdf
87
- def render_pdf_to_file(path)
88
- Payday::PdfRenderer.render_to_file(self, path)
82
+ def render_pdf_to_file(path, appendix: nil)
83
+ Payday::PdfRenderer.render_to_file(self, path, appendix: appendix)
89
84
  end
90
85
 
91
86
  # Iterates through the details on this invoiceable. The block given should accept
92
87
  # two parameters, the detail name and the actual detail value.
93
88
  def each_detail
94
- return if defined?(invoice_details).nil?
89
+ return unless defined?(invoice_details)
95
90
 
96
- invoice_details.each do |detail|
97
- yield(detail[0], detail[1])
98
- end
91
+ invoice_details.each { |detail| yield detail[0], detail[1] }
99
92
  end
100
93
 
101
94
  end
@@ -4,11 +4,9 @@ module Payday
4
4
 
5
5
  # Represents a line item in an invoice.
6
6
  #
7
- # rubocop:todo Layout/LineLength
8
- # +quantity+ and +price+ are written to be pretty picky, primarily because if we're not picky about what values are set to
9
- # rubocop:enable Layout/LineLength
10
- # them your invoice math could get pretty messed up. It's recommended that both values be set to +BigDecimal+ values.
11
- # Otherwise, we'll do our best to convert the set values to a +BigDecimal+.
7
+ # +quantity+ and +price+ are written to be pretty picky, primarily because if we're not picky about what
8
+ # values are set to them your invoice math could get pretty messed up. It's recommended that both values be
9
+ # set to +BigDecimal+ values. Otherwise, we'll do our best to convert the set values to a +BigDecimal+.
12
10
  class LineItem
13
11
 
14
12
  include LineItemable
@@ -31,20 +29,24 @@ module Payday
31
29
 
32
30
  # Sets the quantity of this {LineItem}
33
31
  def quantity=(value)
34
- value = 0 if value.to_s.blank?
35
- @quantity = BigDecimal(value.to_s)
32
+ @quantity = to_decimal(value)
36
33
  end
37
34
 
38
35
  # Sets the price for this {LineItem}
39
36
  def price=(value)
40
- value = 0 if value.to_s.blank?
41
- @price = BigDecimal(value.to_s)
37
+ @price = to_decimal(value)
42
38
  end
43
39
 
44
40
  # Sets the predefined_amount for this {LineItem}
45
41
  def predefined_amount=(value)
46
- value = 0 if value.to_s.blank?
47
- @predefined_amount = BigDecimal(value.to_s)
42
+ @predefined_amount = to_decimal(value)
43
+ end
44
+
45
+ private
46
+
47
+ # A blank value (nil, "", " ") is 0.
48
+ def to_decimal(value)
49
+ BigDecimal(value.to_s.presence || 0)
48
50
  end
49
51
 
50
52
  end
@@ -13,34 +13,29 @@ module Payday
13
13
  FONTS = %w[NotoSans-Regular.ttf NotoSans-Bold.ttf].freeze
14
14
 
15
15
  # Renders the given invoice as a pdf on disk
16
- def self.render_to_file(invoice, path)
17
- File.binwrite(path, render(invoice))
16
+ def self.render_to_file(invoice, path, appendix: nil)
17
+ File.binwrite(path, render(invoice, appendix: appendix))
18
18
  end
19
19
 
20
- # Renders the given invoice as a pdf, returning a string
21
- def self.render(invoice)
22
- new(invoice).render
20
+ # Renders the given invoice as a pdf, returning a string. See Payday::Appendix for
21
+ # appending pages of your own to it.
22
+ def self.render(invoice, appendix: nil)
23
+ new(invoice, appendix: appendix).render
23
24
  end
24
25
 
25
26
  # Converts this number to a formatted currency string
26
27
  def self.number_to_currency(number, invoice)
27
28
  Money.locale_backend = :currency
28
29
  Money.rounding_mode = BigDecimal::ROUND_HALF_UP
29
- currency = Money::Currency.wrap(currency_for(invoice))
30
+ currency = Money::Currency.wrap(Payday::Config.default.value_for(invoice, :currency))
30
31
  number *= currency.subunit_to_unit
31
32
  number = number.round unless Money.default_infinite_precision
32
33
  Money.new(number, currency).format
33
34
  end
34
35
 
35
- def self.currency_for(invoice)
36
- return invoice.currency if invoice.respond_to?(:currency) && invoice.currency
37
-
38
- Payday::Config.default.currency
39
- end
40
- private_class_method :currency_for
41
-
42
- def initialize(invoice)
36
+ def initialize(invoice, appendix: nil)
43
37
  @invoice = invoice
38
+ @appendix = Appendix.wrap(appendix)
44
39
  @dependencies = {}
45
40
  end
46
41
 
@@ -49,20 +44,51 @@ module Payday
49
44
  register_qr_code(data[:qr_code])
50
45
  data[:logo] = logo
51
46
 
52
- Typst(body: File.read(TEMPLATE), dependencies: @dependencies, fonts: fonts,
53
- sys_inputs: {'invoice' => data.to_json})
47
+ Typst(body: body, dependencies: dependencies, fonts: fonts, sys_inputs: sys_inputs(data))
54
48
  .compile(:pdf).bytes.flatten.pack('C*')
55
49
  end
56
50
 
57
51
  private
58
52
 
53
+ # An appendix is concatenated rather than +#include+d, which would make it a module of its
54
+ # own and leave the template's page rules -- the margins, and the numbering footer --
55
+ # stopping at its edge.
56
+ def body
57
+ template = File.read(TEMPLATE)
58
+ return template if @appendix.nil?
59
+
60
+ "#{template}\n#{@appendix.source}"
61
+ end
62
+
63
+ def sys_inputs(data)
64
+ merge({'invoice' => data.to_json}, @appendix&.inputs, 'sys_input')
65
+ end
66
+
67
+ # Read after the logo and the QR code have registered theirs, so an appendix reusing one
68
+ # of those names is caught rather than silently replacing the file.
69
+ def dependencies
70
+ merge(@dependencies, @appendix&.dependencies, 'dependency')
71
+ end
72
+
73
+ def merge(ours, theirs, what)
74
+ return ours if theirs.nil?
75
+
76
+ taken = ours.keys & theirs.keys
77
+ if taken.any?
78
+ raise ArgumentError,
79
+ "appendix #{what} #{taken.map(&:inspect).join(', ')} is reserved by the invoice"
80
+ end
81
+
82
+ ours.merge(theirs)
83
+ end
84
+
59
85
  def fonts
60
86
  FONTS.to_h { |name| [name, File.binread(File.join(FONT_DIR, name))] }
61
87
  end
62
88
 
63
89
  # Config#invoice_logo is either a path or a {filename:, size: "WxH"} Hash.
64
90
  def logo
65
- setting = invoice_logo
91
+ setting = Payday::Config.default.value_for(@invoice, :invoice_logo)
66
92
  return nil if setting.nil?
67
93
 
68
94
  path, width, height = logo_parts(setting)
@@ -71,12 +97,6 @@ module Payday
71
97
  {name: name, width: width, height: height}
72
98
  end
73
99
 
74
- def invoice_logo
75
- return @invoice.invoice_logo if @invoice.respond_to?(:invoice_logo) && @invoice.invoice_logo
76
-
77
- Payday::Config.default.invoice_logo
78
- end
79
-
80
100
  def logo_parts(setting)
81
101
  return [setting, nil, nil] unless setting.is_a?(Hash)
82
102
 
data/payday.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'webtranslateit-payday'
5
- s.version = '2.0.0'
5
+ s.version = '2.1.1'
6
6
  s.required_ruby_version = '>= 3.2'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ['Alan Johnson', 'Edouard Briere']
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webtranslateit-payday
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alan Johnson
@@ -147,6 +147,7 @@ files:
147
147
  - lib/generators/payday/setup/templates/line_item.rb
148
148
  - lib/generators/payday/setup/templates/migration.rb
149
149
  - lib/payday.rb
150
+ - lib/payday/appendix.rb
150
151
  - lib/payday/assets/default_logo.png
151
152
  - lib/payday/config.rb
152
153
  - lib/payday/invoice.rb