invoicing 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -0
  3. data/README.md +57 -0
  4. data/Rakefile +16 -37
  5. data/lib/invoicing.rb +20 -10
  6. data/lib/invoicing/cached_record.rb +9 -6
  7. data/lib/invoicing/class_info.rb +34 -34
  8. data/lib/invoicing/connection_adapter_ext.rb +4 -4
  9. data/lib/invoicing/countries/uk.rb +6 -6
  10. data/lib/invoicing/currency_value.rb +39 -32
  11. data/lib/invoicing/find_subclasses.rb +40 -15
  12. data/lib/invoicing/ledger_item.rb +166 -145
  13. data/lib/invoicing/ledger_item/pdf_generator.rb +108 -0
  14. data/lib/invoicing/ledger_item/render_html.rb +76 -73
  15. data/lib/invoicing/ledger_item/render_ubl.rb +37 -35
  16. data/lib/invoicing/line_item.rb +43 -38
  17. data/lib/invoicing/price.rb +1 -1
  18. data/lib/invoicing/tax_rate.rb +3 -6
  19. data/lib/invoicing/taxable.rb +37 -32
  20. data/lib/invoicing/time_dependent.rb +40 -40
  21. data/lib/invoicing/version.rb +4 -4
  22. data/lib/rails/generators/invoicing/invoicing_generator.rb +14 -0
  23. data/lib/rails/generators/invoicing/ledger_item/ledger_item_generator.rb +17 -0
  24. data/lib/rails/generators/invoicing/ledger_item/templates/migration.rb +25 -0
  25. data/lib/rails/generators/invoicing/ledger_item/templates/model.rb +5 -0
  26. data/lib/rails/generators/invoicing/line_item/line_item_generator.rb +17 -0
  27. data/lib/rails/generators/invoicing/line_item/templates/migration.rb +20 -0
  28. data/lib/rails/generators/invoicing/line_item/templates/model.rb +5 -0
  29. data/lib/rails/generators/invoicing/tax_rate/tax_rate_generator.rb +17 -0
  30. data/lib/rails/generators/invoicing/tax_rate/templates/migration.rb +14 -0
  31. data/lib/rails/generators/invoicing/tax_rate/templates/model.rb +3 -0
  32. metadata +110 -153
  33. data.tar.gz.sig +0 -1
  34. data/History.txt +0 -31
  35. data/Manifest.txt +0 -62
  36. data/PostInstall.txt +0 -10
  37. data/README.rdoc +0 -58
  38. data/script/console +0 -10
  39. data/script/destroy +0 -14
  40. data/script/generate +0 -14
  41. data/tasks/rcov.rake +0 -4
  42. data/test/cached_record_test.rb +0 -100
  43. data/test/class_info_test.rb +0 -253
  44. data/test/connection_adapter_ext_test.rb +0 -79
  45. data/test/currency_value_test.rb +0 -209
  46. data/test/find_subclasses_test.rb +0 -120
  47. data/test/fixtures/README +0 -7
  48. data/test/fixtures/cached_record.sql +0 -22
  49. data/test/fixtures/class_info.sql +0 -28
  50. data/test/fixtures/currency_value.sql +0 -29
  51. data/test/fixtures/find_subclasses.sql +0 -43
  52. data/test/fixtures/ledger_item.sql +0 -39
  53. data/test/fixtures/line_item.sql +0 -33
  54. data/test/fixtures/price.sql +0 -4
  55. data/test/fixtures/tax_rate.sql +0 -4
  56. data/test/fixtures/taxable.sql +0 -14
  57. data/test/fixtures/time_dependent.sql +0 -35
  58. data/test/ledger_item_test.rb +0 -444
  59. data/test/line_item_test.rb +0 -139
  60. data/test/models/README +0 -4
  61. data/test/models/test_subclass_in_another_file.rb +0 -3
  62. data/test/models/test_subclass_not_in_database.rb +0 -6
  63. data/test/price_test.rb +0 -9
  64. data/test/ref-output/creditnote3.html +0 -82
  65. data/test/ref-output/creditnote3.xml +0 -89
  66. data/test/ref-output/invoice1.html +0 -93
  67. data/test/ref-output/invoice1.xml +0 -111
  68. data/test/ref-output/invoice2.html +0 -86
  69. data/test/ref-output/invoice2.xml +0 -98
  70. data/test/ref-output/invoice_null.html +0 -36
  71. data/test/render_html_test.rb +0 -70
  72. data/test/render_ubl_test.rb +0 -44
  73. data/test/setup.rb +0 -37
  74. data/test/tax_rate_test.rb +0 -9
  75. data/test/taxable_test.rb +0 -180
  76. data/test/test_helper.rb +0 -72
  77. data/test/time_dependent_test.rb +0 -180
  78. metadata.gz.sig +0 -4
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 460fa683bd1ba56dede941135a9db41b2b7236cf
4
+ data.tar.gz: 0ab573110cdf7d5c6bb424b2f69880f2f3a6d347
5
+ SHA512:
6
+ metadata.gz: cf54abdd39ade52d2c41ad3757cd4b4b482853bb189e0ac0fe8371a6b5641de5f702557159a61a3d0332a012493b0258420ed7624306b5ff8cb6edb8e306c7b8
7
+ data.tar.gz: 4a41f9ba2236663d0463348cf5880a89e4d54e4d342e59ba147de4d8d33a4a1ba607422112e6b6db2d18d86d68c7c4eeb124eace3c2c9af7ed81451026466edc
data/LICENSE CHANGED
@@ -1,5 +1,6 @@
1
1
  Copyright (c) 2009 Martin Kleppmann
2
2
  Copyright (c) 2009 Ept Computing Limited
3
+ Copyright (c) 2014 Codemancers Tech Pvt Limited
3
4
 
4
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
5
6
  this software and associated documentation files (the "Software"), to deal in
@@ -0,0 +1,57 @@
1
+ # Ruby Invoicing Framework
2
+ [![Build Status](https://travis-ci.org/code-mancers/invoicing.svg?branch=master)](https://travis-ci.org/code-mancers/invoicing)
3
+ [![Code Climate](https://codeclimate.com/github/code-mancers/invoicing.png)](https://codeclimate.com/github/code-mancers/invoicing)
4
+
5
+ ## Description
6
+
7
+ This is a framework for generating and displaying invoices (ideal for commercial
8
+ Rails apps). It allows for flexible business logic; provides tools for tax handling,
9
+ commission calculation etc. It aims to be both developer-friendly and
10
+ accountant-friendly. Please visit invoicing [page](http://invoicing.codemancers.com/)
11
+ for more information about how to install and use.
12
+
13
+ ## Features
14
+
15
+ 1. Store any number of different types of invoice, credit note and payment
16
+ record
17
+ 2. Represent customer accounts, supplier accounts, and even complicated
18
+ multi-party billing relationships
19
+ 3. Automatically format currency values beautifully
20
+ 4. Automatically round currency values to the customary precision for that
21
+ particular currency, e.g. based on the smallest coin in circulation
22
+ 5. Support any number of different currencies simultaneously
23
+ 6. Render invoices, account statements etc. into HTML (fully styleable and
24
+ internationalisable)
25
+ 7. Export into the UBL XML format for sharing data with other systems
26
+ 8. Provide you with a default Value Added Tax (VAT) implementation, but you
27
+ can also easily plug in your own tax logic
28
+ 9. Dynamically display tax-inclusive or tax-exclusive prices depending on
29
+ your customer's location and preferences
30
+ 10. Deal with tax rates or prices changing over time, and automatically
31
+ switch to the new rate at the right moment
32
+ 11. Efficiently summarise account balances, sales statements etc. under
33
+ arbitrary conditions (e.g. data from one quarter, or payments due at a
34
+ particular date)
35
+
36
+ ## TODOs
37
+
38
+ 1. Slowly move away from `acts-as` model.
39
+ 2. Multiple taxes can be applied on goodies.
40
+ 3. Improve documentation for taxes
41
+
42
+
43
+ ## Credits
44
+
45
+ The Ruby invoicing framework originated as part of the website
46
+ [Bid for Wine](http://www.bidforwine.co.uk), developed by Patrick Dietrich,
47
+ Conrad Irwin, Michael Arnold and Martin Kleppmann for Ept Computing Ltd.
48
+ It was extracted from the Bid for Wine codebase and substantially extended
49
+ by Martin Kleppmann.
50
+
51
+ ## License
52
+
53
+ Copyright (c) 2009 Martin Kleppmann, Ept Computing Limited.
54
+ Copyright (c) 2014 Codemancers Tech Pvt Ltd
55
+
56
+ This gem is made publicly available under the terms of the MIT license.
57
+ See LICENSE and/or COPYING for details.
data/Rakefile CHANGED
@@ -1,43 +1,22 @@
1
- %w[rubygems rake rake/clean fileutils newgem rubigen hoe].each { |f| require f }
2
- require File.dirname(__FILE__) + '/lib/invoicing'
3
-
4
- # Hoe calls Ruby with the "-w" set by default; unfortunately, ActiveRecord (at version 2.2.2
5
- # at least) causes a lot of warnings internally, by no fault of our own, which clutters
6
- # the output. Comment out the following four lines to see those warnings.
7
- class Hoe
8
- RUBY_FLAGS = ENV['RUBY_FLAGS'] || "-I#{%w(lib test).join(File::PATH_SEPARATOR)}" +
9
- ((defined?(RUBY_DEBUG) && RUBY_DEBUG) ? " #{RUBY_DEBUG}" : '')
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
10
5
  end
11
6
 
12
- # Generate all the Rake tasks
13
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
14
- $hoe = Hoe.spec 'invoicing' do |p|
15
- p.version = Invoicing::VERSION
16
- p.developer 'Martin Kleppmann', 'rubyforge@eptcomputing.com'
17
-
18
- p.summary = p.paragraphs_of('README.rdoc', 3).join
19
- p.description = p.paragraphs_of('README.rdoc', 3..5).join("\n\n")
20
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
21
- p.post_install_message = 'PostInstall.txt'
22
- p.rubyforge_name = p.name
7
+ require 'rubygems'
8
+ require 'rake'
9
+ require 'rake/clean'
10
+ require 'fileutils'
11
+ require 'rake/testtask'
23
12
 
24
- p.extra_deps = [
25
- ['activerecord', '>= 2.1.0'],
26
- ['builder', '>= 2.0']
27
- ]
28
- p.extra_dev_deps = [
29
- ['newgem', ">= #{::Newgem::VERSION}"]
30
- #['invoicing_generator', "= #{Invoicing::VERSION}"] - causes a circular dependency in rubygems < 1.2
31
- ]
13
+ # Tasks to run by default
14
+ task :default => [:test]
32
15
 
33
- p.test_globs = %w[test/*_test.rb] # do not include test/models/*.rb
34
- p.clean_globs |= %w[**/.DS_Store tmp *.log coverage]
35
- p.rsync_args = '-av --delete --ignore-errors'
36
- p.remote_rdoc_dir = 'doc'
16
+ Rake::TestTask.new do |t|
17
+ t.libs << "test"
18
+ t.test_files = FileList['test/**/*_test.rb']
19
+ t.warning = false
37
20
  end
38
21
 
39
- require 'newgem/tasks' # load /tasks/*.rake
40
- Dir['tasks/**/*.rake'].each { |t| load t }
41
-
42
- # Tasks to run by default
43
- # task :default => [:spec, :features]
22
+ Bundler::GemHelper.install_tasks
@@ -1,12 +1,22 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ require "active_record"
3
2
 
4
- require 'activerecord'
3
+ require "invoicing/class_info" # load first because other modules depend on this
4
+ require "invoicing/cached_record"
5
+ require "invoicing/connection_adapter_ext"
6
+ require "invoicing/currency_value"
7
+ require "invoicing/find_subclasses"
8
+ require "invoicing/ledger_item"
9
+ require "invoicing/line_item"
10
+ require "invoicing/price"
11
+ require "invoicing/tax_rate"
12
+ require "invoicing/taxable"
13
+ require "invoicing/time_dependent"
5
14
 
6
- require 'invoicing/class_info' # load first because other modules depend on this
7
- Dir.glob(File.join(File.dirname(__FILE__), 'invoicing/**/*.rb')).sort.each {|f| require f }
8
-
9
- # Mix all modules Invoicing::*::ActMethods into ActiveRecord::Base as class methods
10
- Invoicing.constants.map{|c| Invoicing.const_get(c) }.select{|m| m.is_a?(Module) && m.const_defined?('ActMethods') }.each{
11
- |m| ActiveRecord::Base.send(:extend, m.const_get('ActMethods'))
12
- }
15
+ ActiveRecord::Base.send(:extend, Invoicing::CachedRecord::ActMethods)
16
+ ActiveRecord::Base.send(:extend, Invoicing::CurrencyValue::ActMethods)
17
+ ActiveRecord::Base.send(:extend, Invoicing::LedgerItem::ActMethods)
18
+ ActiveRecord::Base.send(:extend, Invoicing::LineItem::ActMethods)
19
+ ActiveRecord::Base.send(:extend, Invoicing::Price::ActMethods)
20
+ ActiveRecord::Base.send(:extend, Invoicing::TaxRate::ActMethods)
21
+ ActiveRecord::Base.send(:extend, Invoicing::Taxable::ActMethods)
22
+ ActiveRecord::Base.send(:extend, Invoicing::TimeDependent::ActMethods)
@@ -1,3 +1,5 @@
1
+ require 'active_support/concern'
2
+
1
3
  module Invoicing
2
4
  # == Aggressive ActiveRecord cache
3
5
  #
@@ -20,6 +22,7 @@ module Invoicing
20
22
  # To activate +CachedRecord+, call +acts_as_cached_record+ in the scope of an
21
23
  # <tt>ActiveRecord::Base</tt> class.
22
24
  module CachedRecord
25
+ extend ActiveSupport::Concern
23
26
 
24
27
  module ActMethods
25
28
  # Call +acts_as_cached_record+ on an <tt>ActiveRecord::Base</tt> class to declare
@@ -63,7 +66,7 @@ module Invoicing
63
66
  def cached_record_list
64
67
  cached_record_class_info.list
65
68
  end
66
-
69
+
67
70
  # Reloads the cached objects from the database.
68
71
  def reload_cache
69
72
  cached_record_class_info.reload_cache
@@ -78,12 +81,12 @@ module Invoicing
78
81
  super
79
82
  reload_cache
80
83
  end
81
-
84
+
82
85
  def reload_cache
83
86
  @cache = {}
84
- model_class.find(:all).each {|obj| @cache[get(obj, :id)] = obj }
87
+ model_class.all.each {|obj| @cache[get(obj, :id)] = obj }
85
88
  end
86
-
89
+
87
90
  # Returns one object from the cache, given its ID.
88
91
  def find_one(id, options)
89
92
  if result = @cache[id]
@@ -92,12 +95,12 @@ module Invoicing
92
95
  raise ::ActiveRecord::RecordNotFound, "Couldn't find #{model_class.name} with ID=#{id}"
93
96
  end
94
97
  end
95
-
98
+
96
99
  # Returns a list of objects from the cache, given a list of IDs.
97
100
  def find_some(ids, options)
98
101
  ids.map{|id| find_one(id, options) }
99
102
  end
100
-
103
+
101
104
  # Returns a list of all objects in the cache.
102
105
  def list
103
106
  @cache.values
@@ -18,19 +18,19 @@ module Invoicing
18
18
  # Invoicing::ClassInfo.acts_as(MyNamespace::Teleporter, self, args)
19
19
  # end
20
20
  # end
21
- #
21
+ #
22
22
  # def transmogrify_the_instance # will become an instance method of the class on which the
23
23
  # info = teleporter_class_info # acts_as_ method is called.
24
24
  # info.do_transmogrify
25
25
  # end
26
- #
26
+ #
27
27
  # module ClassMethods
28
28
  # def transmogrify_the_class # will become a class method of the class on which the
29
29
  # info = teleporter_class_info # acts_as_ method is called.
30
30
  # info.do_transmogrify
31
31
  # end
32
32
  # end
33
- #
33
+ #
34
34
  # class ClassInfo < Invoicing::ClassInfo::Base
35
35
  # def do_transmogrify
36
36
  # case all_options[:transmogrification]
@@ -40,7 +40,7 @@ module Invoicing
40
40
  # end
41
41
  # end
42
42
  # end
43
- #
43
+ #
44
44
  # ActiveRecord::Base.send(:extend, MyNamespace::Teleporter::ActMethods)
45
45
  #
46
46
  #
@@ -51,11 +51,11 @@ module Invoicing
51
51
  # class Teleporter < ActiveRecord::Base
52
52
  # acts_as_teleporter 'Zoom2020', :transmogrification => :total
53
53
  # end
54
- #
54
+ #
55
55
  # Teleporter.transmogrify_the_class # both return "Transmogrified by Zoom2020"
56
56
  # Teleporter.find(42).transmogrify_the_instance
57
57
  module ClassInfo
58
-
58
+
59
59
  # Provides the main implementation pattern for an +acts_as_+ method. See the example above
60
60
  # for usage.
61
61
  # +source_module+:: The module object which is using the +ClassInfo+ pattern
@@ -65,28 +65,28 @@ module Invoicing
65
65
  # The name by which the particular module using ClassInfo is known
66
66
  module_name = source_module.name.split('::').last.underscore
67
67
  class_info_method = "#{module_name}_class_info"
68
-
69
- previous_info = if calling_class.private_instance_methods(true).include?(class_info_method)
70
- # acts_as has been called before on the same class, or a superclass
71
- calling_class.send(class_info_method)
72
- else
73
- # acts_as is being called for the first time -- do the mixins!
74
- calling_class.send(:include, source_module)
75
- calling_class.send(:extend, source_module.const_get('ClassMethods')) if source_module.constants.include? 'ClassMethods'
76
- nil # no previous_info
77
- end
78
-
68
+
69
+ previous_info =
70
+ if calling_class.respond_to?(class_info_method, true)
71
+ # acts_as has been called before on the same class, or a superclass
72
+ calling_class.send(class_info_method) || calling_class.superclass.send(class_info_method)
73
+ else
74
+ # acts_as is being called for the first time -- do the mixins!
75
+ calling_class.send(:include, source_module)
76
+ nil # no previous_info
77
+ end
78
+
79
79
  # Instantiate the ClassInfo::Base subclass and assign it to an instance variable in calling_class
80
80
  class_info_class = source_module.const_get('ClassInfo')
81
81
  class_info = class_info_class.new(calling_class, previous_info, args)
82
82
  calling_class.instance_variable_set("@#{class_info_method}", class_info)
83
-
83
+
84
84
  # Define a getter class method on calling_class through which the ClassInfo::Base
85
85
  # instance can be accessed.
86
86
  calling_class.class_eval <<-CLASSEVAL
87
87
  class << self
88
88
  def #{class_info_method}
89
- if superclass.private_instance_methods(true).include?("#{class_info_method}")
89
+ if superclass.respond_to?("#{class_info_method}", true)
90
90
  @#{class_info_method} ||= superclass.send("#{class_info_method}")
91
91
  end
92
92
  @#{class_info_method}
@@ -94,7 +94,7 @@ module Invoicing
94
94
  private "#{class_info_method}"
95
95
  end
96
96
  CLASSEVAL
97
-
97
+
98
98
  # For convenience, also define an instance method which does the same as the class method
99
99
  calling_class.class_eval do
100
100
  define_method class_info_method do
@@ -103,8 +103,8 @@ module Invoicing
103
103
  private class_info_method
104
104
  end
105
105
  end
106
-
107
-
106
+
107
+
108
108
  # Base class for +ClassInfo+ objects, from which you need to derive a subclass in each module where
109
109
  # you want to use +ClassInfo+. An instance of a <tt>ClassInfo::Base</tt> subclass is created every
110
110
  # time an +acts_as_+ method is called, and that instance can be accessed through the
@@ -112,27 +112,27 @@ module Invoicing
112
112
  class Base
113
113
  # The class on which the +acts_as_+ method was called
114
114
  attr_reader :model_class
115
-
115
+
116
116
  # The <tt>ClassInfo::Base</tt> instance created by the last +acts_as_+ method
117
117
  # call on the same class (or its superclass); +nil+ if this is the first call.
118
118
  attr_reader :previous_info
119
-
119
+
120
120
  # The list of arguments passed to the current +acts_as_+ method call (excluding the final options hash)
121
121
  attr_reader :current_args
122
-
122
+
123
123
  # Union of +current_args+ and <tt>previous_info.all_args</tt>
124
124
  attr_reader :all_args
125
-
125
+
126
126
  # <tt>self.all_args - previous_info.all_args</tt>
127
127
  attr_reader :new_args
128
-
128
+
129
129
  # The options hash passed to the current +acts_as_+ method call
130
130
  attr_reader :current_options
131
-
131
+
132
132
  # Hash of options with symbolized keys, with +option_defaults+ overridden by +previous_info+ options,
133
133
  # in turn overridden by +current_options+.
134
134
  attr_reader :all_options
135
-
135
+
136
136
  # Initialises a <tt>ClassInfo::Base</tt> instance and parses arguments.
137
137
  # If subclasses override +initialize+ they should call +super+.
138
138
  # +model_class+:: The class on which the +acts_as+ method was called
@@ -150,26 +150,26 @@ module Invoicing
150
150
  @current_options = args.extract_options!.symbolize_keys
151
151
  @all_options = (@previous_info.nil? ? option_defaults : @previous_info.all_options).clone
152
152
  @all_options.update(@current_options)
153
-
153
+
154
154
  @all_args = @new_args = @current_args = args.flatten.uniq
155
155
  unless @previous_info.nil?
156
156
  @all_args = (@previous_info.all_args + @all_args).uniq
157
157
  @new_args = @all_args - previous_info.all_args
158
158
  end
159
159
  end
160
-
160
+
161
161
  # Override this method to return a hash of default option values.
162
162
  def option_defaults
163
163
  {}
164
164
  end
165
-
165
+
166
166
  # If there is an option with the given key, returns the associated value; otherwise returns
167
167
  # the key. This is useful for mapping method names to their renamed equivalents through options.
168
168
  def method(name)
169
169
  name = name.to_sym
170
170
  (all_options[name] || name).to_s
171
171
  end
172
-
172
+
173
173
  # Returns the value returned by calling +method_name+ (renamed through options using +method+)
174
174
  # on +object+. Returns +nil+ if +object+ is +nil+ or +object+ does not respond to that method.
175
175
  def get(object, method_name)
@@ -184,4 +184,4 @@ module Invoicing
184
184
  end
185
185
  end
186
186
  end
187
- end
187
+ end
@@ -2,20 +2,20 @@ module Invoicing
2
2
  # Extensions specific to certain database adapters. Currently only MySQL and PostgreSQL are
3
3
  # supported.
4
4
  class ConnectionAdapterExt
5
-
5
+
6
6
  # Creates a database-specific SQL fragment for evaluating a three-legged conditional function
7
7
  # in a query.
8
8
  def self.conditional_function(condition, value_if_true, value_if_false)
9
9
  case ActiveRecord::Base.connection.adapter_name
10
10
  when "MySQL"
11
11
  "IF(#{condition}, #{value_if_true}, #{value_if_false})"
12
- when "PostgreSQL"
12
+ when "PostgreSQL", "SQLite"
13
13
  "CASE WHEN #{condition} THEN #{value_if_true} ELSE #{value_if_false} END"
14
14
  else
15
15
  raise "Database adapter #{ActiveRecord::Base.connection.adapter_name} not supported by invoicing gem"
16
16
  end
17
17
  end
18
-
18
+
19
19
  # Suppose <tt>A has_many B</tt>, and you want to select all As, counting for each A how many
20
20
  # Bs it has. In MySQL you can just say:
21
21
  # SELECT A.*, COUNT(B.id) AS number_of_bs FROM A LEFT JOIN B on A.id = B.a_id GROUP BY A.id
@@ -32,7 +32,7 @@ module Invoicing
32
32
  when "MySQL"
33
33
  model_class.quoted_table_name + "." +
34
34
  ActiveRecord::Base.connection.quote_column_name(model_class.primary_key)
35
- when "PostgreSQL"
35
+ when "PostgreSQL", "SQLite"
36
36
  model_class.column_names.map{ |column|
37
37
  model_class.quoted_table_name + "." + ActiveRecord::Base.connection.quote_column_name(column)
38
38
  }.join(', ')
@@ -6,27 +6,27 @@ module Invoicing
6
6
  def tax_rate(params)
7
7
  params[:model_object].send(:tax_rate)
8
8
  end
9
-
9
+
10
10
  def tax_factor(params)
11
11
  BigDecimal('1') + tax_rate(params).rate
12
12
  end
13
-
13
+
14
14
  def tax_percent(params)
15
15
  BigDecimal('100') * tax_rate(params).rate
16
16
  end
17
-
17
+
18
18
  def apply_tax(params)
19
19
  params[:value] * tax_factor(params)
20
20
  end
21
-
21
+
22
22
  def remove_tax(params)
23
23
  params[:value] / tax_factor(params)
24
24
  end
25
-
25
+
26
26
  def tax_info(params)
27
27
  "(inc. VAT)"
28
28
  end
29
-
29
+
30
30
  def tax_details(params)
31
31
  "(including VAT at #{tax_percent(params).to_s}%)"
32
32
  end