invoicing 0.1.0
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.
- data/CHANGELOG +3 -0
- data/LICENSE +20 -0
- data/Manifest +60 -0
- data/README +48 -0
- data/Rakefile +75 -0
- data/invoicing.gemspec +41 -0
- data/lib/invoicing.rb +9 -0
- data/lib/invoicing/cached_record.rb +107 -0
- data/lib/invoicing/class_info.rb +187 -0
- data/lib/invoicing/connection_adapter_ext.rb +44 -0
- data/lib/invoicing/countries/uk.rb +24 -0
- data/lib/invoicing/currency_value.rb +212 -0
- data/lib/invoicing/find_subclasses.rb +193 -0
- data/lib/invoicing/ledger_item.rb +718 -0
- data/lib/invoicing/ledger_item/render_html.rb +515 -0
- data/lib/invoicing/ledger_item/render_ubl.rb +268 -0
- data/lib/invoicing/line_item.rb +246 -0
- data/lib/invoicing/price.rb +9 -0
- data/lib/invoicing/tax_rate.rb +9 -0
- data/lib/invoicing/taxable.rb +355 -0
- data/lib/invoicing/time_dependent.rb +388 -0
- data/lib/invoicing/version.rb +21 -0
- data/test/cached_record_test.rb +100 -0
- data/test/class_info_test.rb +253 -0
- data/test/connection_adapter_ext_test.rb +71 -0
- data/test/currency_value_test.rb +184 -0
- data/test/find_subclasses_test.rb +120 -0
- data/test/fixtures/README +7 -0
- data/test/fixtures/cached_record.sql +22 -0
- data/test/fixtures/class_info.sql +28 -0
- data/test/fixtures/currency_value.sql +29 -0
- data/test/fixtures/find_subclasses.sql +43 -0
- data/test/fixtures/ledger_item.sql +39 -0
- data/test/fixtures/line_item.sql +33 -0
- data/test/fixtures/price.sql +4 -0
- data/test/fixtures/tax_rate.sql +4 -0
- data/test/fixtures/taxable.sql +14 -0
- data/test/fixtures/time_dependent.sql +35 -0
- data/test/ledger_item_test.rb +352 -0
- data/test/line_item_test.rb +139 -0
- data/test/models/README +4 -0
- data/test/models/test_subclass_in_another_file.rb +3 -0
- data/test/models/test_subclass_not_in_database.rb +6 -0
- data/test/price_test.rb +9 -0
- data/test/ref-output/creditnote3.html +82 -0
- data/test/ref-output/creditnote3.xml +89 -0
- data/test/ref-output/invoice1.html +93 -0
- data/test/ref-output/invoice1.xml +111 -0
- data/test/ref-output/invoice2.html +86 -0
- data/test/ref-output/invoice2.xml +98 -0
- data/test/ref-output/invoice_null.html +36 -0
- data/test/render_html_test.rb +69 -0
- data/test/render_ubl_test.rb +32 -0
- data/test/setup.rb +37 -0
- data/test/tax_rate_test.rb +9 -0
- data/test/taxable_test.rb +180 -0
- data/test/test_helper.rb +48 -0
- data/test/time_dependent_test.rb +180 -0
- data/website/curvycorners.js +1 -0
- data/website/screen.css +149 -0
- data/website/template.html.erb +43 -0
- metadata +180 -0
@@ -0,0 +1,515 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'builder'
|
4
|
+
|
5
|
+
module Invoicing
|
6
|
+
module LedgerItem
|
7
|
+
# Included into ActiveRecord model object when +acts_as_ledger_item+ is invoked.
|
8
|
+
module RenderHTML
|
9
|
+
# Shortcut for rendering an invoice or a credit note into a human-readable HTML format.
|
10
|
+
# Can be called without any arguments, in which case a general-purpose representation is
|
11
|
+
# produced. Can also be given options and a block for customising the output:
|
12
|
+
#
|
13
|
+
# @invoice = Invoice.find(params[:id])
|
14
|
+
# @invoice.render_html :quantity_column => false do |i|
|
15
|
+
# i.date_format "%d %B %Y" # overwrites default "%Y-%m-%d"
|
16
|
+
# i.recipient_label "Customer" # overwrites default "Recipient"
|
17
|
+
# i.sender_label "Supplier" # overwrites default "Sender"
|
18
|
+
# i.description_tag do |params|
|
19
|
+
# "<p>Thank you for your order. Here is our invoice for your records.</p>\n" +
|
20
|
+
# "<p>Description: #{params[:description]}</p>\n"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
def render_html(options={}, &block)
|
24
|
+
output_builder = HTMLOutputBuilder.new(self, options)
|
25
|
+
yield output_builder if block_given?
|
26
|
+
output_builder.build
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
class HTMLOutputBuilder #:nodoc:
|
31
|
+
|
32
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
33
|
+
|
34
|
+
attr_reader :ledger_item, :current_line_item, :options, :custom_fragments, :factor
|
35
|
+
|
36
|
+
def initialize(ledger_item, options)
|
37
|
+
@ledger_item = ledger_item
|
38
|
+
@options = default_options
|
39
|
+
@options.update(options)
|
40
|
+
@custom_fragments = {}
|
41
|
+
total_amount = get(:total_amount)
|
42
|
+
@factor = (total_amount && total_amount < BigDecimal('0')) ? BigDecimal('-1') : BigDecimal('1')
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_options
|
46
|
+
line_items = get(:line_items)
|
47
|
+
{
|
48
|
+
:tax_point_column => line_items.map{|i| line_get(:tax_point, i) }.compact != [],
|
49
|
+
:quantity_column => line_items.map{|i| line_get(:quantity, i) }.compact != [],
|
50
|
+
:description_column => true,
|
51
|
+
:net_amount_column => true,
|
52
|
+
:tax_amount_column => line_items.map{|i| line_get(:tax_amount, i) }.compact != [],
|
53
|
+
:gross_amount_column => false,
|
54
|
+
:subtotal => true
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def h(s)
|
59
|
+
s.to_s.gsub(/[#{HTML_ESCAPE.keys.join}]/) { |char| HTML_ESCAPE[char] }
|
60
|
+
end
|
61
|
+
|
62
|
+
# foo { block } => call block when invoking fragment foo
|
63
|
+
# foo "string" => return string when invoking fragment foo
|
64
|
+
# invoke_foo => invoke fragment foo; if none set, delegate to default_foo
|
65
|
+
def method_missing(method_id, *args, &block)
|
66
|
+
method_id = method_id.to_sym
|
67
|
+
if method_id.to_s =~ /^invoke_(.*)$/
|
68
|
+
method_id = $1.to_sym
|
69
|
+
if custom_fragments[method_id]
|
70
|
+
return custom_fragments[method_id].call(*args, &block)
|
71
|
+
else
|
72
|
+
return send("default_#{method_id}", *args, &block)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
return super unless respond_to? "default_#{method_id}"
|
77
|
+
|
78
|
+
if block_given? && args.empty?
|
79
|
+
custom_fragments[method_id] = proc &block
|
80
|
+
elsif args.length == 1
|
81
|
+
custom_fragments[method_id] = proc{ args[0].to_s }
|
82
|
+
else
|
83
|
+
raise ArgumentError, "#{method_id} expects exactly one value or block argument"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns the value of a (potentially renamed) method on the ledger item
|
88
|
+
def get(method_id)
|
89
|
+
ledger_item.send(:ledger_item_class_info).get(ledger_item, method_id)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the value of a (potentially renamed) method on a line item
|
93
|
+
def line_get(method_id, line_item = current_line_item)
|
94
|
+
line_item.send(:line_item_class_info).get(line_item, method_id)
|
95
|
+
end
|
96
|
+
|
97
|
+
# String for one level of indentation
|
98
|
+
def indent
|
99
|
+
' '
|
100
|
+
end
|
101
|
+
|
102
|
+
# This is quite meta. :)
|
103
|
+
#
|
104
|
+
# params_hash(:sender_label, :sender_tax_number => :tax_number_label)
|
105
|
+
# # => {:sender_label => invoke_sender_label,
|
106
|
+
# # :sender_tax_number => invoke_sender_tax_number(params_hash(:tax_number_label))}
|
107
|
+
def params_hash(*param_names)
|
108
|
+
result = {}
|
109
|
+
param_names.flatten!
|
110
|
+
options = param_names.extract_options!
|
111
|
+
|
112
|
+
param_names.each{|param| result[param.to_sym] = send("invoke_#{param}") }
|
113
|
+
|
114
|
+
options.each_pair do |key, value|
|
115
|
+
result[key.to_sym] = send("invoke_#{key}", params_hash(value))
|
116
|
+
end
|
117
|
+
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
# Renders an invoice or credit note to HTML
|
122
|
+
def build
|
123
|
+
addresses_table_deps = [:sender_label, :recipient_label, :sender_address, :recipient_address, {
|
124
|
+
:sender_tax_number => :tax_number_label,
|
125
|
+
:recipient_tax_number => :tax_number_label
|
126
|
+
}]
|
127
|
+
|
128
|
+
metadata_table_deps = [{
|
129
|
+
:identifier => :identifier_label,
|
130
|
+
:issue_date => [:date_format, :issue_date_label],
|
131
|
+
:period_start => [:date_format, :period_start_label],
|
132
|
+
:period_end => [:date_format, :period_end_label],
|
133
|
+
:due_date => [:date_format, :due_date_label]
|
134
|
+
}]
|
135
|
+
|
136
|
+
line_items_header_deps = [:line_tax_point_label, :line_quantity_label, :line_description_label,
|
137
|
+
:line_net_amount_label, :line_tax_amount_label, :line_gross_amount_label]
|
138
|
+
|
139
|
+
line_items_subtotal_deps = [:subtotal_label, :net_amount_label, :tax_amount_label,
|
140
|
+
:gross_amount_label, {
|
141
|
+
:net_amount => :net_amount_label,
|
142
|
+
:tax_amount => :tax_amount_label,
|
143
|
+
:total_amount => :gross_amount_label
|
144
|
+
}]
|
145
|
+
|
146
|
+
line_items_total_deps = [:total_label, :net_amount_label, :tax_amount_label,
|
147
|
+
:gross_amount_label, {
|
148
|
+
:net_amount => :net_amount_label,
|
149
|
+
:tax_amount => :tax_amount_label,
|
150
|
+
:total_amount => :gross_amount_label
|
151
|
+
}]
|
152
|
+
|
153
|
+
page_layout_deps = {
|
154
|
+
:title_tag => :title,
|
155
|
+
:addresses_table => addresses_table_deps,
|
156
|
+
:metadata_table => metadata_table_deps,
|
157
|
+
:description_tag => :description,
|
158
|
+
:line_items_table => [:line_items_list, {
|
159
|
+
:line_items_header => line_items_header_deps,
|
160
|
+
:line_items_subtotal => line_items_subtotal_deps,
|
161
|
+
:line_items_total => line_items_total_deps
|
162
|
+
}]
|
163
|
+
}
|
164
|
+
|
165
|
+
invoke_page_layout(params_hash(page_layout_deps))
|
166
|
+
end
|
167
|
+
|
168
|
+
def default_date_format
|
169
|
+
"%Y-%m-%d"
|
170
|
+
end
|
171
|
+
|
172
|
+
def default_invoice_label
|
173
|
+
"Invoice"
|
174
|
+
end
|
175
|
+
|
176
|
+
def default_credit_note_label
|
177
|
+
"Credit Note"
|
178
|
+
end
|
179
|
+
|
180
|
+
def default_recipient_label
|
181
|
+
"Recipient"
|
182
|
+
end
|
183
|
+
|
184
|
+
def default_sender_label
|
185
|
+
"Sender"
|
186
|
+
end
|
187
|
+
|
188
|
+
def default_tax_number_label
|
189
|
+
"VAT number:<br />"
|
190
|
+
end
|
191
|
+
|
192
|
+
def default_identifier_label
|
193
|
+
"Invoice no.:"
|
194
|
+
end
|
195
|
+
|
196
|
+
def default_issue_date_label
|
197
|
+
"Issue date:"
|
198
|
+
end
|
199
|
+
|
200
|
+
def default_period_start_label
|
201
|
+
"Period from:"
|
202
|
+
end
|
203
|
+
|
204
|
+
def default_period_end_label
|
205
|
+
"Period until:"
|
206
|
+
end
|
207
|
+
|
208
|
+
def default_due_date_label
|
209
|
+
"Payment due:"
|
210
|
+
end
|
211
|
+
|
212
|
+
def default_line_tax_point_label
|
213
|
+
"Tax point"
|
214
|
+
end
|
215
|
+
|
216
|
+
def default_line_quantity_label
|
217
|
+
"Quantity"
|
218
|
+
end
|
219
|
+
|
220
|
+
def default_line_description_label
|
221
|
+
"Description"
|
222
|
+
end
|
223
|
+
|
224
|
+
def default_line_net_amount_label
|
225
|
+
"Net price"
|
226
|
+
end
|
227
|
+
|
228
|
+
def default_line_tax_amount_label
|
229
|
+
"VAT"
|
230
|
+
end
|
231
|
+
|
232
|
+
def default_line_gross_amount_label
|
233
|
+
"Gross price"
|
234
|
+
end
|
235
|
+
|
236
|
+
def default_subtotal_label
|
237
|
+
"Subtotal"
|
238
|
+
end
|
239
|
+
|
240
|
+
def default_total_label
|
241
|
+
"Total"
|
242
|
+
end
|
243
|
+
|
244
|
+
def default_net_amount_label
|
245
|
+
"Net: "
|
246
|
+
end
|
247
|
+
|
248
|
+
def default_tax_amount_label
|
249
|
+
"VAT: "
|
250
|
+
end
|
251
|
+
|
252
|
+
def default_gross_amount_label
|
253
|
+
""
|
254
|
+
end
|
255
|
+
|
256
|
+
def default_title
|
257
|
+
(factor == BigDecimal('-1')) ? invoke_credit_note_label : invoke_invoice_label
|
258
|
+
end
|
259
|
+
|
260
|
+
def default_title_tag(params)
|
261
|
+
"<h1 class=\"invoice\">#{params[:title]}</h1>\n"
|
262
|
+
end
|
263
|
+
|
264
|
+
def default_address(details)
|
265
|
+
html = "#{indent*3}<div class=\"fn org\">#{ h(details[:name]) }</div>\n"
|
266
|
+
html << "#{indent*3}<div class=\"contact\">#{ h(details[:contact_name])}</div>\n" unless details[:contact_name].blank?
|
267
|
+
html << "#{indent*3}<div class=\"adr\">\n"
|
268
|
+
html << "#{indent*4}<span class=\"street-address\">#{h(details[:address]).strip.gsub(/\n/, '<br />')}</span><br />\n"
|
269
|
+
html << "#{indent*4}<span class=\"locality\">#{ h(details[:city]) }</span><br />\n" unless details[:city].blank?
|
270
|
+
html << "#{indent*4}<span class=\"region\">#{ h(details[:state]) }</span><br />\n" unless details[:state].blank?
|
271
|
+
html << "#{indent*4}<span class=\"postal-code\">#{ h(details[:postal_code]) }</span><br />\n" unless details[:postal_code].blank?
|
272
|
+
html << "#{indent*4}<span class=\"country-name\">#{h(details[:country]) }</span>\n" unless details[:country].blank?
|
273
|
+
html << "#{indent*3}</div>\n"
|
274
|
+
end
|
275
|
+
|
276
|
+
def default_sender_address
|
277
|
+
invoke_address(get(:sender_details))
|
278
|
+
end
|
279
|
+
|
280
|
+
def default_recipient_address
|
281
|
+
invoke_address(get(:recipient_details))
|
282
|
+
end
|
283
|
+
|
284
|
+
def default_sender_tax_number(params)
|
285
|
+
sender_tax_number = get(:sender_details)[:tax_number]
|
286
|
+
"#{params[:tax_number_label]}<span class=\"tax-number\">#{h(sender_tax_number)}</span>"
|
287
|
+
end
|
288
|
+
|
289
|
+
def default_recipient_tax_number(params)
|
290
|
+
recipient_tax_number = get(:recipient_details)[:tax_number]
|
291
|
+
"#{params[:tax_number_label]}<span class=\"tax-number\">#{h(recipient_tax_number)}</span>"
|
292
|
+
end
|
293
|
+
|
294
|
+
def default_addresses_table(params)
|
295
|
+
html = "#{indent*0}<table class=\"invoice addresses\">\n"
|
296
|
+
html << "#{indent*1}<tr>\n"
|
297
|
+
html << "#{indent*2}<th class=\"recipient\">#{params[:recipient_label]}</th>\n"
|
298
|
+
html << "#{indent*2}<th class=\"sender\">#{params[:sender_label]}</th>\n"
|
299
|
+
html << "#{indent*1}</tr>\n"
|
300
|
+
html << "#{indent*1}<tr>\n"
|
301
|
+
html << "#{indent*2}<td class=\"recipient vcard\">\n#{params[:recipient_address]}"
|
302
|
+
html << "#{indent*2}</td>\n"
|
303
|
+
html << "#{indent*2}<td class=\"sender vcard\">\n#{params[:sender_address]}"
|
304
|
+
html << "#{indent*2}</td>\n"
|
305
|
+
html << "#{indent*1}</tr>\n"
|
306
|
+
html << "#{indent*1}<tr>\n"
|
307
|
+
html << "#{indent*2}<td class=\"recipient\">\n"
|
308
|
+
html << "#{indent*3}#{params[:recipient_tax_number]}\n"
|
309
|
+
html << "#{indent*2}</td>\n"
|
310
|
+
html << "#{indent*2}<td class=\"sender\">\n"
|
311
|
+
html << "#{indent*3}#{params[:sender_tax_number]}\n"
|
312
|
+
html << "#{indent*2}</td>\n"
|
313
|
+
html << "#{indent*1}</tr>\n"
|
314
|
+
html << "#{indent*0}</table>\n"
|
315
|
+
end
|
316
|
+
|
317
|
+
def default_metadata_item(params, key, value)
|
318
|
+
label = params["#{key}_label".to_sym]
|
319
|
+
html = "#{indent*1}<tr class=\"#{key.to_s.gsub(/_/, '-')}\">\n"
|
320
|
+
html << "#{indent*2}<th>#{label}</th>\n"
|
321
|
+
html << "#{indent*2}<td>#{h(value)}</td>\n"
|
322
|
+
html << "#{indent*1}</tr>\n"
|
323
|
+
end
|
324
|
+
|
325
|
+
def default_identifier(params)
|
326
|
+
invoke_metadata_item(params, :identifier, get(:identifier))
|
327
|
+
end
|
328
|
+
|
329
|
+
def default_issue_date(params)
|
330
|
+
if issue_date = get(:issue_date)
|
331
|
+
invoke_metadata_item(params, :issue_date, issue_date.strftime(params[:date_format]))
|
332
|
+
else
|
333
|
+
""
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def default_period_start(params)
|
338
|
+
if period_start = get(:period_start)
|
339
|
+
invoke_metadata_item(params, :period_start, period_start.strftime(params[:date_format]))
|
340
|
+
else
|
341
|
+
""
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def default_period_end(params)
|
346
|
+
if period_end = get(:period_end)
|
347
|
+
invoke_metadata_item(params, :period_end, period_end.strftime(params[:date_format]))
|
348
|
+
else
|
349
|
+
""
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def default_due_date(params)
|
354
|
+
if due_date = get(:due_date)
|
355
|
+
invoke_metadata_item(params, :due_date, due_date.strftime(params[:date_format]))
|
356
|
+
else
|
357
|
+
""
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def default_metadata_table(params)
|
362
|
+
"<table class=\"invoice metadata\">\n" + params[:identifier] + params[:issue_date] +
|
363
|
+
params[:period_start] + params[:period_end] + params[:due_date] + "#{indent*0}</table>\n"
|
364
|
+
end
|
365
|
+
|
366
|
+
def default_description
|
367
|
+
h(get(:description))
|
368
|
+
end
|
369
|
+
|
370
|
+
def default_description_tag(params)
|
371
|
+
"<p class=\"invoice description\">#{params[:description]}</p>\n"
|
372
|
+
end
|
373
|
+
|
374
|
+
def default_line_items_header(params)
|
375
|
+
html = "#{indent*1}<tr>\n"
|
376
|
+
html << "#{indent*2}<th class=\"tax-point\">#{ params[:line_tax_point_label] }</th>\n" if options[:tax_point_column]
|
377
|
+
html << "#{indent*2}<th class=\"quantity\">#{ params[:line_quantity_label] }</th>\n" if options[:quantity_column]
|
378
|
+
html << "#{indent*2}<th class=\"description\">#{ params[:line_description_label] }</th>\n" if options[:description_column]
|
379
|
+
html << "#{indent*2}<th class=\"net-amount\">#{ params[:line_net_amount_label] }</th>\n" if options[:net_amount_column]
|
380
|
+
html << "#{indent*2}<th class=\"tax-amount\">#{ params[:line_tax_amount_label] }</th>\n" if options[:tax_amount_column]
|
381
|
+
html << "#{indent*2}<th class=\"gross-amount\">#{params[:line_gross_amount_label]}</th>\n" if options[:gross_amount_column]
|
382
|
+
html << "#{indent*1}</tr>\n"
|
383
|
+
end
|
384
|
+
|
385
|
+
def default_line_tax_point(params)
|
386
|
+
if tax_point = line_get(:tax_point)
|
387
|
+
h(tax_point.strftime(params[:date_format]))
|
388
|
+
else
|
389
|
+
""
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
def default_line_quantity(params)
|
394
|
+
h(line_get(:quantity).to_s)
|
395
|
+
end
|
396
|
+
|
397
|
+
def default_line_description(params)
|
398
|
+
h(line_get(:description))
|
399
|
+
end
|
400
|
+
|
401
|
+
def default_line_net_amount(params)
|
402
|
+
if net_amount = line_get(:net_amount)
|
403
|
+
h(current_line_item.format_currency_value(net_amount*factor))
|
404
|
+
else
|
405
|
+
"—"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def default_line_tax_amount(params)
|
410
|
+
if tax_amount = line_get(:tax_amount)
|
411
|
+
h(current_line_item.format_currency_value(tax_amount*factor))
|
412
|
+
else
|
413
|
+
"—"
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def default_line_gross_amount(params)
|
418
|
+
if gross_amount = line_get(:gross_amount)
|
419
|
+
h(current_line_item.format_currency_value(gross_amount*factor))
|
420
|
+
else
|
421
|
+
"—"
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
def default_net_amount(params)
|
426
|
+
if net_amount = get(:net_amount)
|
427
|
+
h(ledger_item.format_currency_value(net_amount*factor))
|
428
|
+
else
|
429
|
+
"—"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
def default_tax_amount(params)
|
434
|
+
if tax_amount = get(:tax_amount)
|
435
|
+
h(ledger_item.format_currency_value(tax_amount*factor))
|
436
|
+
else
|
437
|
+
"—"
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def default_total_amount(params)
|
442
|
+
if total_amount = get(:total_amount)
|
443
|
+
h(ledger_item.format_currency_value(total_amount*factor))
|
444
|
+
else
|
445
|
+
"—"
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def default_line_item(params)
|
450
|
+
html = "#{indent*1}<tr>\n"
|
451
|
+
html << "#{indent*2}<td class=\"tax-point\">#{ params[:line_tax_point] }</td>\n" if options[:tax_point_column]
|
452
|
+
html << "#{indent*2}<td class=\"quantity\">#{ params[:line_quantity] }</td>\n" if options[:quantity_column]
|
453
|
+
html << "#{indent*2}<td class=\"description\">#{ params[:line_description] }</td>\n" if options[:description_column]
|
454
|
+
html << "#{indent*2}<td class=\"net-amount\">#{ params[:line_net_amount] }</td>\n" if options[:net_amount_column]
|
455
|
+
html << "#{indent*2}<td class=\"tax-amount\">#{ params[:line_tax_amount] }</td>\n" if options[:tax_amount_column]
|
456
|
+
html << "#{indent*2}<td class=\"gross-amount\">#{params[:line_gross_amount]}</td>\n" if options[:gross_amount_column]
|
457
|
+
html << "#{indent*1}</tr>\n"
|
458
|
+
end
|
459
|
+
|
460
|
+
def default_line_items_list
|
461
|
+
get(:line_items).sorted(:tax_point).map do |line_item|
|
462
|
+
@current_line_item = line_item
|
463
|
+
invoke_line_item(params_hash(
|
464
|
+
:line_tax_point => [:line_tax_point_label, :date_format],
|
465
|
+
:line_quantity => [:line_quantity_label],
|
466
|
+
:line_description => [:line_description_label],
|
467
|
+
:line_net_amount => [:line_net_amount_label],
|
468
|
+
:line_tax_amount => [:line_tax_amount_label],
|
469
|
+
:line_gross_amount => [:line_gross_amount_label]
|
470
|
+
))
|
471
|
+
end.join
|
472
|
+
end
|
473
|
+
|
474
|
+
def default_line_items_subtotal(params)
|
475
|
+
colspan = 0
|
476
|
+
colspan += 1 if options[:tax_point_column]
|
477
|
+
colspan += 1 if options[:quantity_column]
|
478
|
+
colspan += 1 if options[:description_column]
|
479
|
+
html = "#{indent*1}<tr class=\"subtotal\">\n"
|
480
|
+
html << "#{indent*2}<th colspan=\"#{colspan}\">#{params[:subtotal_label]}</th>\n"
|
481
|
+
html << "#{indent*2}<td class=\"net-amount\">#{params[:net_amount_label]}#{params[:net_amount]}</td>\n" if options[:net_amount_column]
|
482
|
+
html << "#{indent*2}<td class=\"tax-amount\">#{params[:tax_amount_label]}#{params[:tax_amount]}</td>\n" if options[:tax_amount_column]
|
483
|
+
html << "#{indent*2}<td class=\"gross-amount\"></td>\n" if options[:gross_amount_column]
|
484
|
+
html << "#{indent*1}</tr>\n"
|
485
|
+
end
|
486
|
+
|
487
|
+
def default_line_items_total(params)
|
488
|
+
colspan = -1
|
489
|
+
colspan += 1 if options[:tax_point_column]
|
490
|
+
colspan += 1 if options[:quantity_column]
|
491
|
+
colspan += 1 if options[:description_column]
|
492
|
+
colspan += 1 if options[:net_amount_column]
|
493
|
+
colspan += 1 if options[:tax_amount_column]
|
494
|
+
colspan += 1 if options[:gross_amount_column]
|
495
|
+
html = "#{indent*1}<tr class=\"total\">\n"
|
496
|
+
html << "#{indent*2}<th colspan=\"#{colspan}\">#{params[:total_label]}</th>\n"
|
497
|
+
html << "#{indent*2}<td class=\"total-amount\">#{params[:gross_amount_label]}#{params[:total_amount]}</td>\n"
|
498
|
+
html << "#{indent*1}</tr>\n"
|
499
|
+
end
|
500
|
+
|
501
|
+
def default_line_items_table(params)
|
502
|
+
html = "<table class=\"invoice line-items\">\n"
|
503
|
+
html << params[:line_items_header] + params[:line_items_list]
|
504
|
+
html << params[:line_items_subtotal] if options[:subtotal]
|
505
|
+
html << params[:line_items_total] + "</table>\n"
|
506
|
+
end
|
507
|
+
|
508
|
+
def default_page_layout(params)
|
509
|
+
params[:title_tag] + params[:addresses_table] + params[:metadata_table] +
|
510
|
+
params[:description_tag] + params[:line_items_table]
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|