invoicing_generator 0.2.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.
Files changed (32) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +21 -0
  3. data/LICENSE +20 -0
  4. data/Manifest.txt +29 -0
  5. data/PostInstall.txt +10 -0
  6. data/README.rdoc +55 -0
  7. data/Rakefile +25 -0
  8. data/lib/invoicing_generator.rb +18 -0
  9. data/lib/invoicing_generator/generator_extensions.rb +55 -0
  10. data/lib/invoicing_generator/name_tools.rb +83 -0
  11. data/lib/invoicing_generator/option_tools.rb +34 -0
  12. data/rails_generators/invoicing_ledger/USAGE +20 -0
  13. data/rails_generators/invoicing_ledger/invoicing_ledger_generator.rb +107 -0
  14. data/rails_generators/invoicing_ledger/templates/controller.rb +40 -0
  15. data/rails_generators/invoicing_ledger/templates/credit_note.rb +1 -0
  16. data/rails_generators/invoicing_ledger/templates/initializer.rb +2 -0
  17. data/rails_generators/invoicing_ledger/templates/invoice.rb +1 -0
  18. data/rails_generators/invoicing_ledger/templates/ledger_item.rb +49 -0
  19. data/rails_generators/invoicing_ledger/templates/ledger_view.html +26 -0
  20. data/rails_generators/invoicing_ledger/templates/line_item.rb +7 -0
  21. data/rails_generators/invoicing_ledger/templates/migration.rb +63 -0
  22. data/rails_generators/invoicing_ledger/templates/payment.rb +1 -0
  23. data/rails_generators/invoicing_ledger/templates/statement_view.html +48 -0
  24. data/rails_generators/invoicing_ledger/templates/stylesheet.css +127 -0
  25. data/script/console +10 -0
  26. data/script/destroy +14 -0
  27. data/script/generate +14 -0
  28. data/test/test_generator_helper.rb +36 -0
  29. data/test/test_helper.rb +3 -0
  30. data/test/test_invoicing_ledger_generator.rb +46 -0
  31. metadata +138 -0
  32. metadata.gz.sig +0 -0
Binary file
@@ -0,0 +1,21 @@
1
+ == 0.2.0 2009-04-20
2
+
3
+ * 4 major enhancements:
4
+ * New associated gem invoicing_generator for generating an invoicing component in a Rails project
5
+ (script/generate invoicing_ledger)
6
+ * Generated controller and views for rendering statements and ledger
7
+ * Comes with a nice default stylesheet out of the box
8
+ * More flexible formatting of currency values
9
+ * 1 bugfix:
10
+ * Accidental overwriting of total_amount value on payment LedgerItems without LineItems
11
+
12
+ == 0.1.0 2009-02-10
13
+
14
+ * 2 major enhancements:
15
+ * Core API is now usable
16
+ * RCov reports 100% test coverage
17
+
18
+ == 0.0.1 2009-01-05
19
+
20
+ * 1 major enhancement:
21
+ * Initial public release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Martin Kleppmann
2
+ Copyright (c) 2009 Ept Computing Limited
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,29 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ PostInstall.txt
5
+ README.rdoc
6
+ Rakefile
7
+ lib/invoicing_generator.rb
8
+ lib/invoicing_generator/generator_extensions.rb
9
+ lib/invoicing_generator/name_tools.rb
10
+ lib/invoicing_generator/option_tools.rb
11
+ rails_generators/invoicing_ledger/USAGE
12
+ rails_generators/invoicing_ledger/invoicing_ledger_generator.rb
13
+ rails_generators/invoicing_ledger/templates/controller.rb
14
+ rails_generators/invoicing_ledger/templates/credit_note.rb
15
+ rails_generators/invoicing_ledger/templates/initializer.rb
16
+ rails_generators/invoicing_ledger/templates/invoice.rb
17
+ rails_generators/invoicing_ledger/templates/ledger_item.rb
18
+ rails_generators/invoicing_ledger/templates/ledger_view.html
19
+ rails_generators/invoicing_ledger/templates/line_item.rb
20
+ rails_generators/invoicing_ledger/templates/migration.rb
21
+ rails_generators/invoicing_ledger/templates/payment.rb
22
+ rails_generators/invoicing_ledger/templates/statement_view.html
23
+ rails_generators/invoicing_ledger/templates/stylesheet.css
24
+ script/console
25
+ script/destroy
26
+ script/generate
27
+ test/test_generator_helper.rb
28
+ test/test_helper.rb
29
+ test/test_invoicing_ledger_generator.rb
@@ -0,0 +1,10 @@
1
+
2
+ Thanks for trying the Ruby Invoicing Gem. Hope you find it useful.
3
+ Do please blog and tweet about it (tag your posts with #invgem).
4
+
5
+ Now please go to the root of your Rails project and type:
6
+ script/generate invoicing_ledger billing --currency=GBP
7
+ (replace GBP with your currency if you do not use Pounds Sterling).
8
+ For more information please go to http://ept.github.com/invoicing/
9
+
10
+
@@ -0,0 +1,55 @@
1
+ = Ruby Invoicing Framework
2
+
3
+ * {Ruby Invoicing Framework website}[http://ept.github.com/invoicing/]
4
+ * {API Reference Docs}[http://invoicing.rubyforge.org/doc/]
5
+ * {Browse the code on GitHub}[http://github.com/ept/invoicing/]
6
+ * {RubyForge project}[http://rubyforge.org/projects/invoicing/]
7
+ * Email: Martin Kleppmann <ept@rubyforge.org>
8
+
9
+ == DESCRIPTION
10
+
11
+ This is a framework for generating and displaying invoices (ideal for
12
+ commercial Rails apps). It allows for flexible business logic; provides tools
13
+ for tax handling, commission calculation etc. It aims to be both
14
+ developer-friendly and accountant-friendly.
15
+
16
+ The Ruby Invoicing Framework is based on
17
+ {ActiveRecord}[http://api.rubyonrails.org/classes/ActiveRecord/Base.html].
18
+
19
+ Please see {the website}[http://ept.github.com/invoicing/] for an introduction
20
+ to using Invoicing, and check the
21
+ {API reference}[http://invoicing.rubyforge.org/doc/] for in-depth details.
22
+
23
+ == FEATURES
24
+
25
+ * TODO
26
+
27
+ == REQUIREMENTS
28
+
29
+ * ActiveRecord >= 2.1
30
+ * Only MySQL and PostgreSQL databases are currently supported
31
+
32
+ == INSTALL
33
+
34
+ sudo gem install invoicing
35
+
36
+ == STATUS
37
+
38
+ So far, the Ruby Invoicing Framework has been tested with ActiveRecord 2.2.2,
39
+ MySQL 5.0.67 and PostgreSQL 8.3.5. We will be testing it across a wider
40
+ variety of versions soon.
41
+
42
+ == CREDITS
43
+
44
+ The Ruby invoicing framework originated as part of the website
45
+ {Bid for Wine}[http://www.bidforwine.co.uk], developed by Patrick Dietrich,
46
+ Conrad Irwin, Michael Arnold and Martin Kleppmann for Ept Computing Ltd.
47
+ It was extracted from the Bid for Wine codebase and substantially extended
48
+ by Martin Kleppmann.
49
+
50
+ == LICENSE
51
+
52
+ Copyright (c) 2009 Martin Kleppmann, Ept Computing Limited.
53
+
54
+ This gem is made publicly available under the terms of the MIT license.
55
+ See LICENSE and/or COPYING for details.
@@ -0,0 +1,25 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/invoicing_generator'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('invoicing_generator', InvoicingGenerator::VERSION) do |p|
7
+ p.developer('Martin Kleppmann', 'rubyforge@eptcomputing.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt'
10
+ p.rubyforge_name = 'invoicing'
11
+ p.extra_deps = [
12
+ ['invoicing', "= #{InvoicingGenerator::VERSION}"],
13
+ ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
@@ -0,0 +1,18 @@
1
+ [
2
+ File.dirname(__FILE__),
3
+ File.join(File.dirname(__FILE__), '..', '..', 'invoicing', 'lib')
4
+ ].each do |dir|
5
+ unless !File.exists?(dir) || $:.include?(dir) || $:.include?(File.expand_path(dir))
6
+ $:.unshift dir
7
+ end
8
+ end
9
+
10
+ require 'invoicing'
11
+
12
+ require 'invoicing_generator/generator_extensions'
13
+ require 'invoicing_generator/name_tools'
14
+ require 'invoicing_generator/option_tools'
15
+
16
+ module InvoicingGenerator
17
+ VERSION = Invoicing::VERSION
18
+ end
@@ -0,0 +1,55 @@
1
+ # Inject a custom command into the rails generator -- useful for rendering classes
2
+ # nested inside modules.
3
+ module Rails #:nodoc:
4
+ module Generator
5
+ module Commands
6
+ class Create
7
+ # A bit like the 'template' method, but wraps the rendered template output in a Ruby
8
+ # class definition, potentially nested in one or more module definitions.
9
+ # +class_details+ should be a hash in the form returned by
10
+ # InvoicingGenerator::NameTools#extract_name_details, detailing information about
11
+ # the class and to which file it should be written.
12
+ def nested_class_template(relative_source, class_details, template_options = {})
13
+ # Render the relative_source template
14
+ inside_template = render_file(source_path(relative_source), template_options) do |file|
15
+ vars = template_options[:assigns] || {}
16
+ b = binding
17
+ vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
18
+ # Render the source file with the temporary binding
19
+ ERB.new(file.read, nil, '-').result(b)
20
+ end
21
+
22
+ # Prepare class and module definitions
23
+ nesting = class_details[:class_nesting_array]
24
+ index = -1
25
+ header = nesting.map{|mod| index += 1; (' ' * index) + "module #{mod}\n"}.join
26
+ header << (' ' * nesting.size) + "class #{class_details[:class_name_base]}"
27
+ header << " < #{class_details[:superclass]}" unless [nil, ''].include? class_details[:superclass]
28
+ header << "\n"
29
+ footer = (0..nesting.size).to_a.reverse.map{|n| (' ' * n) + "end\n"}.join
30
+ indent = ' ' * (nesting.size + 1)
31
+
32
+ # Write everything to file
33
+ file(relative_source, class_details[:file_path_full], template_options) do
34
+ header + inside_template.split("\n").map{|line| "#{indent}#{line}"}.join("\n") + "\n" + footer
35
+ end
36
+ end
37
+
38
+ # Based on the 'route_resources' method, but less restrictive. Adds arbitrary lines to
39
+ # the config/routes.rb file.
40
+ def add_routes(*lines)
41
+ text = (lines.flatten.map do |line|
42
+ line.strip!
43
+ logger.route line
44
+ " #{line}\n"
45
+ end).join
46
+
47
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
48
+ unless options[:pretend]
49
+ gsub_file('config/routes.rb', /(#{Regexp.escape(sentinel)})/mi) {|match| "#{match}\n#{text}" }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,83 @@
1
+ # Tools for dealing with names of controllers or models, passed to us by the user
2
+ # from the command line when invoking the generator. Designed to be included into
3
+ # a subclass of Rails::Generator::NamedBase.
4
+ #
5
+ # This code is inspired by the generator in restful_authentication.
6
+ module InvoicingGenerator
7
+ module NameTools
8
+
9
+ # Analyses a name provided by the user on the command line, and returns a hash
10
+ # of useful bits of string based on that name:
11
+ # extract_name_details 'MegaBlurb/foo/BAR_BLOBS', :kind => :controller, :extension => '.rb'
12
+ # => {
13
+ # :underscore_base => 'bar_blobs', # last part of the name, underscored
14
+ # :camel_base => 'BarBlobs', # last part of the name, camelized
15
+ # :underscore_singular => 'bar_blob', # underscore_base forced to singular form
16
+ # :camel_singular => 'BarBlob', # camel_base forced to singular form
17
+ # :underscore_plural => 'bar_blobs', # underscore_base forced to plural form
18
+ # :camel_plural => 'BarBlobs', # camel_base forced to plural form
19
+ # :class_path_array => ['mega_blurb', 'foo'], # array of lowercase, underscored directory names
20
+ # :class_path => 'mega_blurb/foo', # class_path_array joined by filesystem separator
21
+ # :class_nesting_array => ['MegaBlurb', 'Foo'], # array of camelized module names
22
+ # :class_nesting => 'MegaBlurb::Foo', # class_nesting_array joined by double colon
23
+ # :nesting_depth => 2, # length of class_path array
24
+ #
25
+ # # The following depend on the given :kind
26
+ #  :file_path_base => 'bar_blobs_controller.rb' # based on underscore_*
27
+ # :file_path_full => 'app/controllers/mega_blurb/foo/bar_blobs_controller.rb', # full file path
28
+ # :class_name_base => 'BarBlobsController', # file_path_base.camelize
29
+ # :class_name_full => 'MegaBlurb::Foo::BarBlobsController', # = class_nesting + class_name_base
30
+ # }
31
+ #
32
+ # Recognised options:
33
+ # :kind => :model -- use conventions for creating a model object from the name
34
+ # :kind => :controller -- use conventions for creating a controller from the name
35
+ def extract_name_details(user_specified_name, options={})
36
+ result = {}
37
+
38
+ # See Rails::Generator::NamedBase#extract_modules
39
+ modules = extract_modules(user_specified_name)
40
+ base_name = modules.shift
41
+ result[:class_path_array] = modules.shift
42
+ file_path = modules.shift
43
+ result[:class_nesting] = modules.shift
44
+ result[:nesting_depth] = modules.shift
45
+ result[:class_path] = File.join(result[:class_path_array])
46
+ result[:class_nesting_array] = result[:class_nesting].split('::')
47
+
48
+ result[:underscore_base] = base_name.underscore
49
+ result[:camel_base] = result[:underscore_base].camelize
50
+ result[:underscore_singular] = result[:underscore_base].singularize
51
+ result[:camel_singular] = result[:underscore_singular].camelize
52
+ result[:underscore_plural] = result[:underscore_singular].pluralize
53
+ result[:camel_plural] = result[:underscore_plural].camelize
54
+
55
+ if options[:kind] == :controller
56
+ result[:file_path_base] = "#{result[:underscore_base]}_controller"
57
+ path_prefix = File.join('app', 'controllers')
58
+ elsif options[:kind] == :model
59
+ result[:file_path_base] = result[:underscore_singular]
60
+ path_prefix = File.join('app', 'models')
61
+ else
62
+ raise 'unknown kind of name'
63
+ end
64
+
65
+ result[:class_name_base] = result[:file_path_base].camelize
66
+ result[:file_path_base] += (options[:extension] || ".rb")
67
+
68
+ if result[:nesting_depth] == 0
69
+ result[:file_path_full] = File.join(path_prefix, result[:file_path_base])
70
+ result[:class_name_full] = result[:class_name_base]
71
+ else
72
+ result[:file_path_full] = File.join(path_prefix, result[:class_path], result[:file_path_base])
73
+ result[:class_name_full] = "#{result[:class_nesting]}::#{result[:class_name_base]}"
74
+ end
75
+
76
+ #result[:routing_name] = result[:singular_name]
77
+ #result[:routing_path] = result[:file_path].singularize
78
+ #result[:controller_name] = result[:plural_name]
79
+
80
+ result
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,34 @@
1
+ # Tools for parsing command line options. Designed to be included into
2
+ # a subclass of Rails::Generator::NamedBase.
3
+ module InvoicingGenerator
4
+ module OptionTools
5
+ protected
6
+
7
+ # Overrides Rails::Generator::Options#add_options!
8
+ # Expects with_or_without_options to be defined in the importing class.
9
+ def add_options!(opt)
10
+ opt.separator ''
11
+ opt.separator 'Optional flags:'
12
+ with_or_without_options.each_pair do |key, val|
13
+ opt.on "--with-#{key}", val + (options[key] ? " (default)" : "") do
14
+ options[key] = true
15
+ end
16
+ opt.on "--without-#{key}", "don't #{val}" + (options[key] ? " (default)" : "") do
17
+ options[key] = false
18
+ end
19
+ end
20
+ opt.on("--debug", "print debugging output") { options[:debug] = true }
21
+ end
22
+
23
+ # Output debugging info
24
+ def dump_details
25
+ name_details.each_pair do |key1, val1|
26
+ puts "#{key1}:"
27
+ val1.each_pair do |key2, val2|
28
+ puts " %-40s %s" % ["#{key2}:", val2.inspect]
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ Description:
2
+ Generates several model classes, a database migration, a controller and a
3
+ few views in a Rails project, constituting the core structure you need in
4
+ order to make use of the invoicing gem in your application.
5
+
6
+ Once you have this structure in place you can start creating your own
7
+ Invoice and LineItem subclasses and store them in the database; the
8
+ generated controller/views will pick these up and present them nicely
9
+ out of the box.
10
+
11
+ You can use the option flags to configure which fields you would like to
12
+ include in your database tables.
13
+
14
+ After running this generator you should take a look at the generated
15
+ controller and model classes and search for occurrences of 'FIXME', since
16
+ a few manual tweaks will be required to integrate the generated code into
17
+ your project.
18
+
19
+ Examples:
20
+ `./script/generate invoicing_ledger billing --currency=GBP`
@@ -0,0 +1,107 @@
1
+ require 'invoicing_generator'
2
+
3
+ # Rails generator which creates the migration, models and a controller to support a basic ledger.
4
+ class InvoicingLedgerGenerator < Rails::Generator::NamedBase
5
+
6
+ include InvoicingGenerator::NameTools
7
+ include InvoicingGenerator::OptionTools
8
+
9
+ default_options :description => true, :period => true, :uuid => true, :due_date => true,
10
+ :tax_point => true, :quantity => true, :creator => true, :identifier => false,
11
+ :timestamps => true, :debug => false
12
+
13
+ attr_reader :name_details
14
+
15
+ def initialize(runtime_args, runtime_options = {})
16
+ super
17
+ @name_details = {
18
+ :controller => extract_name_details(@name, :kind => :controller),
19
+ :ledger_item => extract_name_details(args.shift || 'Billing::LedgerItem', :kind => :model),
20
+ :line_item => extract_name_details(args.shift || 'Billing::LineItem', :kind => :model)
21
+ }
22
+ subclass_nesting = name_details[:ledger_item][:class_nesting]
23
+ subclass_nesting << '::' unless subclass_nesting == ''
24
+ name_details[:invoice] = extract_name_details("#{subclass_nesting}Invoice", :kind => :model)
25
+ name_details[:credit_note] = extract_name_details("#{subclass_nesting}CreditNote", :kind => :model)
26
+ name_details[:payment] = extract_name_details("#{subclass_nesting}Payment", :kind => :model)
27
+
28
+ name_details[:controller ][:superclass] = 'ApplicationController'
29
+ name_details[:ledger_item][:superclass] = 'ActiveRecord::Base'
30
+ name_details[:invoice ][:superclass] = name_details[:ledger_item][:class_name_base]
31
+ name_details[:credit_note][:superclass] = name_details[:ledger_item][:class_name_base]
32
+ name_details[:payment ][:superclass] = name_details[:ledger_item][:class_name_base]
33
+ name_details[:line_item ][:superclass] = 'ActiveRecord::Base'
34
+
35
+ dump_details if options[:debug]
36
+ end
37
+
38
+ def manifest
39
+ record do |m|
40
+ name_details.each_pair do |key, details|
41
+ # Check for class naming collisions.
42
+ m.class_collisions details[:class_path_array], details[:class_name_base]
43
+
44
+ # Create directories
45
+ m.directory File.dirname(details[:file_path_full])
46
+
47
+ # Create classes
48
+ m.nested_class_template "#{key}.rb", details, :assigns => { :name_details => name_details }
49
+ end
50
+
51
+ # Migration
52
+ m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => 'create_invoicing_ledger'
53
+
54
+ # Static files
55
+ m.directory 'config/initializers'
56
+ m.file 'initializer.rb', 'config/initializers/invoicing.rb'
57
+ view_directory = File.join('app/views', name_details[:controller][:underscore_base])
58
+ m.directory view_directory
59
+ m.file 'statement_view.html', File.join(view_directory, 'statement.html.erb')
60
+ m.file 'ledger_view.html', File.join(view_directory, 'ledger.html.erb')
61
+ m.file 'stylesheet.css', File.join('public/stylesheets', 'invoicing_ledger.css')
62
+
63
+ # Routes
64
+ ctrl = name_details[:controller][:underscore_base]
65
+ m.add_routes(
66
+ "map.ledger '#{ctrl}/:id/ledger', :controller => '#{ctrl}', :action => 'ledger'",
67
+ "map.statement '#{ctrl}/:id/:other_id', :controller => '#{ctrl}', :action => 'statement', :id => /\\d+/, :other_id => nil",
68
+ "map.document '#{ctrl}/document/:id', :controller => '#{ctrl}', :action => 'document'"
69
+ )
70
+ end
71
+ end
72
+
73
+ protected
74
+ def banner
75
+ <<-EOS
76
+ Creates the model classes and migration for a ledger of accounting data.
77
+
78
+ USAGE: #{$0} invoicing_ledger ControllerName [LedgerItemsModelName] [LineItemsModelName] [options]
79
+
80
+ The recommended ControllerName is 'Billing'.
81
+ The default model names are 'Billing::LedgerItem' and 'Billing::LineItem', respectively.
82
+ EOS
83
+ end
84
+
85
+ def with_or_without_options
86
+ {
87
+ :description => "create a description column for ledger and line items",
88
+ :period => "create start_period/end_period columns for ledger items",
89
+ :uuid => "create uuid columns for ledger and line items",
90
+ :due_date => "create a due_date column for ledger items",
91
+ :tax_point => "create a tax_point column for line items",
92
+ :quantity => "create a quantity column for line items",
93
+ :creator => "create a creator_id column for line items",
94
+ :identifier => "create an identifier column for ledger items",
95
+ :timestamps => "create created_at/updated_at columns"
96
+ }
97
+ end
98
+
99
+ def add_options!(opt)
100
+ super
101
+ opt.separator ''
102
+ opt.separator 'Optional configuration values:'
103
+ opt.on "--currency=CODE", "set a default currency (3-letter code, e.g. USD or GBP)" do |currency|
104
+ options[:currency] = currency.nil? ? nil : currency.upcase
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,40 @@
1
+ # GET /<%= name_details[:controller][:underscore_base] %>
2
+ def index
3
+ # We suggest that you make this a redirect to the ledger or statement of the currently
4
+ # logged-in party, e.g.
5
+ #redirect_to ledger_url(current_user.company)
6
+ end
7
+
8
+ # Display a summary of sales, purchases, payments and receipts on accounts.
9
+ # GET /<%= name_details[:controller][:underscore_base] %>/1/ledger => From the point of view of party 1
10
+ def ledger
11
+ # FIXME check if the current user is allowed to access this ledger
12
+ @self_id = params[:id].to_i
13
+ @summaries = <%= name_details[:ledger_item][:class_name_full] %>.account_summaries(@self_id)
14
+ @names = <%= name_details[:ledger_item][:class_name_full] %>.sender_recipient_name_map(@self_id, @summaries.keys)
15
+ end
16
+
17
+ # GET /<%= name_details[:controller][:underscore_base] %>/1 => Show list of transactions where 1 is sender_id or recipient_id
18
+ # GET /<%= name_details[:controller][:underscore_base] %>/1/2 => Show list of transactions between parties 1 and 2
19
+ def statement
20
+ # FIXME check if the current user is allowed to access this account statement
21
+ @self_id = params[:id].to_i
22
+ scope = <%= name_details[:ledger_item][:class_name_full] %>.exclude_empty_invoices.sent_or_received_by(@self_id).sorted(:issue_date)
23
+ scope = scope.sent_or_received_by(params[:other_id]) if params[:other_id]
24
+ @in_effect = scope.in_effect.all
25
+ @open_or_pending = scope.open_or_pending.all
26
+ @summary = <%= name_details[:ledger_item][:class_name_full] %>.account_summary(@self_id, params[:other_id])
27
+ end
28
+
29
+ # Display an invoice or credit note.
30
+ # GET /<%= name_details[:controller][:underscore_base] %>/document/1
31
+ # GET /<%= name_details[:controller][:underscore_base] %>/document/1.xml
32
+ def document
33
+ # FIXME check if the current user is allowed to access this ledger item
34
+ @<%= name_details[:ledger_item][:underscore_singular] %> = <%= name_details[:ledger_item][:class_name_full] %>.find(params[:id])
35
+
36
+ respond_to do |format|
37
+ format.html { render :text => @<%= name_details[:ledger_item][:underscore_singular] %>.render_html, :layout => true }
38
+ format.xml { render :xml => @<%= name_details[:ledger_item][:underscore_singular] %>.render_ubl }
39
+ end
40
+ end
@@ -0,0 +1,2 @@
1
+ # Load the invoicing gem
2
+ require 'invoicing'
@@ -0,0 +1,49 @@
1
+ <% if name_details[:line_item][:underscore_plural] != 'line_items' -%>
2
+ acts_as_ledger_item :line_items => :<%= name_details[:line_item][:underscore_plural] %>
3
+ <% else -%>
4
+ acts_as_ledger_item
5
+ <% end -%>
6
+
7
+ has_many :<%= name_details[:line_item][:underscore_plural] %>, :class_name => '<%= name_details[:line_item][:class_name_full] %>'
8
+
9
+ # Change the following associations to refer to your customer or supplier model class
10
+ #belongs_to :sender, :class_name => 'FIXME'
11
+ #belongs_to :recipient, :class_name => 'FIXME'
12
+
13
+ # Returns a hash containing details about the sender of this invoice, credit note or payment. This allows
14
+ # you to integrate the invoicing gem with your existing model objects for users and customers/suppliers.
15
+ #
16
+ # The returned hash should have the following keys:
17
+ # <tt>:is_self</tt>:: +true+ if these details refer to yourself, i.e. the person or organsiation who owns/operates
18
+ # this application. +false+ if these details refer to any other party.
19
+ # <tt>:name</tt>:: The name of the person or organisation whose billing address is defined below.
20
+ # <tt>:contact_name</tt>:: The name of a person/department within the organisation named by <tt>:name</tt>.
21
+ # <tt>:address</tt>:: The body of the billing address (not including city, postcode, state and country); may be
22
+ # a multi-line string, with lines separated by '\n' line breaks.
23
+ # <tt>:city</tt>:: The name of the city or town in the billing address.
24
+ # <tt>:state</tt>:: The state/region/province/county of the billing address as appropriate.
25
+ # <tt>:postal_code</tt>:: The postal code of the billing address (e.g. ZIP code in the US).
26
+ # <tt>:country</tt>:: The billing address country (human-readable).
27
+ # <tt>:country_code</tt>:: The two-letter country code of the billing address, according to
28
+ # ISO-3166-1[http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2].
29
+ # <tt>:tax_number</tt>:: The Value Added Tax registration code of this person or organisation, if they have
30
+ # one, preferably including the country identifier at the beginning. This is important for
31
+ # transactions within the European Union.
32
+ def sender_details
33
+ raise 'FIXME: you must implement <%= name_details[:ledger_item][:class_name_full] %>#sender_details'
34
+ end
35
+
36
+ # Returns a hash containing details about the recipient of this invoice, credit note or payment,
37
+ # in the same format as returned by +sender_details+.
38
+ def recipient_details
39
+ raise 'FIXME: you must implement <%= name_details[:ledger_item][:class_name_full] %>#recipient_details'
40
+ end
41
+
42
+ <% if !options[:identifier] -%>
43
+ # Returns the user-visible identifier for a document, e.g. the invoice number. The default is to simply
44
+ # use the primary key generated by the database, but if you want to customise invoice numbers, you can
45
+ # also create a database column called 'identifier'.
46
+ def identifier
47
+ id
48
+ end
49
+ <% end -%>
@@ -0,0 +1,26 @@
1
+ <h1 class="ledger">Sales and purchase ledger</h1>
2
+
3
+ <table class="ledger">
4
+ <tr>
5
+ <th class="name">Name</th>
6
+ <th class="currency">Currency</th>
7
+ <th class="sales">Sales</th>
8
+ <th class="purchases">Purchases</th>
9
+ <th class="sale-receipts">Sale Receipts</th>
10
+ <th class="purchase-payments">Purchase Payments</th>
11
+ <th class="balance">Balance</th>
12
+ </tr>
13
+ <% @summaries.keys.sort.each do |id| -%>
14
+ <% @summaries[id].keys.sort.each do |currency| -%>
15
+ <tr>
16
+ <td class="name"><%= link_to h(@names[id]), statement_path(:id => @self_id, :other_id => id) %></td>
17
+ <td class="currency"><%=h currency %></td>
18
+ <td class="sales"><%=h @summaries[id][currency].sales_formatted %></td>
19
+ <td class="purchases"><%=h @summaries[id][currency].purchases_formatted %></td>
20
+ <td class="sale-receipts"><%=h @summaries[id][currency].sale_receipts_formatted %></td>
21
+ <td class="purchase-payments"><%=h @summaries[id][currency].purchase_payments_formatted %></td>
22
+ <td class="balance"><%=h @summaries[id][currency].balance_formatted %></td>
23
+ </tr>
24
+ <% end -%>
25
+ <% end -%>
26
+ </table>
@@ -0,0 +1,7 @@
1
+ <% if name_details[:ledger_item][:underscore_singular] != 'ledger_item' -%>
2
+ acts_as_line_item :ledger_item => :<%= name_details[:ledger_item][:underscore_singular] %>
3
+ <% else -%>
4
+ acts_as_line_item
5
+ <% end -%>
6
+
7
+ belongs_to :<%= name_details[:ledger_item][:underscore_singular] %>, :class_name => '<%= name_details[:ledger_item][:class_name_full] %>'
@@ -0,0 +1,63 @@
1
+ class CreateInvoicingLedger < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= name_details[:ledger_item][:underscore_plural] %> do |t|
4
+ t.string :type
5
+ t.integer :sender_id
6
+ t.integer :recipient_id
7
+ t.datetime :issue_date
8
+ t.string :currency, :limit => 3, :null => false<%= options[:currency] ? ", :default => '#{options[:currency]}'" : '' %>
9
+ t.decimal :total_amount, :precision => 20, :scale => 4
10
+ t.decimal :tax_amount, :precision => 20, :scale => 4
11
+ t.string :status, :limit => 20
12
+ <% if options[:identifier] -%>
13
+ t.string :identifier, :limit => 50
14
+ <% end -%>
15
+ <% if options[:description] -%>
16
+ t.string :description
17
+ <% end -%>
18
+ <% if options[:period] -%>
19
+ t.datetime :period_start
20
+ t.datetime :period_end
21
+ <% end -%>
22
+ <% if options[:uuid] -%>
23
+ t.string :uuid, :limit => 40
24
+ <% end -%>
25
+ <% if options[:due_date] -%>
26
+ t.datetime :due_date
27
+ <% end -%>
28
+ <% if options[:timestamps] -%>
29
+ t.timestamps
30
+ <% end -%>
31
+ end
32
+
33
+ create_table :<%= name_details[:line_item][:underscore_plural] %> do |t|
34
+ t.string :type
35
+ t.references :<%= name_details[:ledger_item][:underscore_singular] %>
36
+ t.decimal :net_amount, :precision => 20, :scale => 4
37
+ t.decimal :tax_amount, :precision => 20, :scale => 4
38
+ <% if options[:description] -%>
39
+ t.string :description
40
+ <% end -%>
41
+ <% if options[:uuid] -%>
42
+ t.string :uuid, :limit => 40
43
+ <% end -%>
44
+ <% if options[:tax_point] -%>
45
+ t.datetime :tax_point
46
+ <% end -%>
47
+ <% if options[:quantity] -%>
48
+ t.decimal :quantity, :precision => 20, :scale => 4
49
+ <% end -%>
50
+ <% if options[:creator] -%>
51
+ t.integer :creator_id
52
+ <% end -%>
53
+ <% if options[:timestamps] -%>
54
+ t.timestamps
55
+ <% end -%>
56
+ end
57
+ end
58
+
59
+ def self.down
60
+ drop_table :<%= name_details[:line_item][:underscore_plural] %>
61
+ drop_table :<%= name_details[:ledger_item][:underscore_plural] %>
62
+ end
63
+ end
@@ -0,0 +1,48 @@
1
+ <h1 class="statement">Account statement</h1>
2
+
3
+ <% unless @in_effect.empty? %>
4
+ <table class="statement in_effect">
5
+ <tr>
6
+ <th class="number">No.</th>
7
+ <th class="date">Date</th>
8
+ <th class="description">Description</th>
9
+ <th class="amount">Amount</th>
10
+ </tr>
11
+ <% for document in @in_effect %>
12
+ <tr>
13
+ <td class="number"><%= h document.identifier %></td>
14
+ <td class="date"><%= h (document.issue_date || document.updated_at).strftime('%Y-%m-%d') %></td>
15
+ <td class="description">
16
+ <% if document.class.is_payment -%>
17
+ <%= h document.description %>
18
+ <% else -%>
19
+ <%= link_to h(document.description), document_path(document) %>
20
+ <% end -%>
21
+ </td>
22
+ <td class="amount"><%= h document.total_amount_formatted(:debit => :negative, :self_id => @self_id) %></td>
23
+ </tr>
24
+ <% end %>
25
+ <% @summary.each_pair do |currency, balances| %>
26
+ <tr class="balance">
27
+ <th colspan="3">Balance due (<%= h currency %>)</th>
28
+ <td class="amount"><%= balances.balance_formatted %></td>
29
+ </tr>
30
+ <% end %>
31
+ </table>
32
+ <% end %>
33
+
34
+ <% unless @open_or_pending.empty? %>
35
+ <h2 class="statement open_or_pending">Charges not yet invoiced</h2>
36
+ <table class="statement open_or_pending">
37
+ <tr>
38
+ <th class="description">Description</th>
39
+ <th class="amount">Amount</th>
40
+ </tr>
41
+ <% for document in @open_or_pending %>
42
+ <tr>
43
+ <td class="description"><%= link_to h(document.description), document_path(document) %></td>
44
+ <td class="amount"><%= h document.total_amount_formatted(:debit => :negative, :self_id => @self_id) %></td>
45
+ </tr>
46
+ <% end %>
47
+ </table>
48
+ <% end %>
@@ -0,0 +1,127 @@
1
+ table.invoice {
2
+ width: 800px;
3
+ }
4
+
5
+ table.invoice td, table.invoice th {
6
+ vertical-align: top;
7
+ }
8
+
9
+ table.invoice.addresses {
10
+ table-layout: fixed;
11
+ text-align: left;
12
+ }
13
+
14
+ table.invoice.addresses td, table.invoice.addresses th {
15
+ padding: 0.5em;
16
+ }
17
+
18
+ table.invoice.addresses td.vcard {
19
+ border: 1px solid black;
20
+ }
21
+
22
+ table.invoice.metadata {
23
+ table-layout: fixed;
24
+ margin: 2em 0 1em 0;
25
+ }
26
+
27
+ table.invoice.metadata tr {
28
+ text-align: right;
29
+ }
30
+
31
+ table.invoice.metadata td {
32
+ width: 20%;
33
+ text-align: left;
34
+ }
35
+
36
+ p.invoice.description {
37
+ font-weight: bold;
38
+ background-color: #eee;
39
+ width: 800px;
40
+ padding: 0.5em;
41
+ }
42
+
43
+ table.invoice.line-items {
44
+ border-collapse: collapse;
45
+ empty-cells: show;
46
+ margin-bottom: 5em;
47
+ }
48
+
49
+ table.invoice.line-items td, table.invoice.line-items th {
50
+ border: 1px solid black;
51
+ padding: 0.5em;
52
+ text-align: left;
53
+ }
54
+
55
+ table.invoice.line-items td.net-amount, table.invoice.line-items th.net-amount,
56
+ table.invoice.line-items td.tax-amount, table.invoice.line-items th.tax-amount {
57
+ text-align: right;
58
+ }
59
+
60
+ table.invoice.line-items tr.subtotal td, table.invoice.line-items tr.subtotal th {
61
+ padding-top: 3em;
62
+ text-align: right;
63
+ }
64
+
65
+ table.invoice.line-items tr.total td, table.invoice.line-items tr.total th {
66
+ padding-top: 2em;
67
+ text-align: right;
68
+ font-weight: bold;
69
+ }
70
+
71
+
72
+
73
+
74
+ table.ledger {
75
+ border-collapse: collapse;
76
+ empty-cells: show;
77
+ margin: 2em 0 5em;
78
+ table-layout: fixed;
79
+ width: 900px;
80
+ }
81
+
82
+ table.ledger td, table.ledger th {
83
+ border: 1px solid black;
84
+ padding: 0.5em;
85
+ text-align: right;
86
+ vertical-align: top;
87
+ }
88
+
89
+ table.ledger td.name, table.ledger th.name {
90
+ text-align: left;
91
+ width: 25%;
92
+ }
93
+
94
+
95
+
96
+ table.statement {
97
+ border-collapse: collapse;
98
+ empty-cells: show;
99
+ margin: 2em 0 5em;
100
+ table-layout: fixed;
101
+ width: 800px;
102
+ }
103
+
104
+ table.statement td, table.statement th {
105
+ border: 1px solid black;
106
+ padding: 0.5em;
107
+ text-align: left;
108
+ vertical-align: top;
109
+ }
110
+
111
+ table.statement td.number, table.statement th.number {
112
+ width: 5%;
113
+ }
114
+
115
+ table.statement td.date, table.statement th.date,
116
+ table.statement td.amount, table.statement th.amount {
117
+ width: 15%;
118
+ }
119
+
120
+ table.statement td.amount, table.statement th.amount {
121
+ text-align: right;
122
+ }
123
+
124
+ table.statement tr.balance td, table.statement tr.balance th {
125
+ text-align: right;
126
+ font-weight: bold;
127
+ }
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/invoicing_generator.rb'}"
9
+ puts "Loading invoicing_generator gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,36 @@
1
+ begin
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+ rescue LoadError
4
+ require 'test/unit'
5
+ end
6
+ require 'fileutils'
7
+
8
+ # Load generator libs in the form needed for generating a new rails project
9
+ gem 'rails'
10
+ require 'rails/version'
11
+ require 'rails_generator'
12
+ require 'rails_generator/scripts/generate'
13
+
14
+ # Configure the path of the temporary rails project in which our component
15
+ # generators will be run in tests.
16
+ TMP_ROOT = File.dirname(__FILE__) + "/tmp" unless defined?(TMP_ROOT)
17
+ PROJECT_NAME = "myproject" unless defined?(PROJECT_NAME)
18
+ app_root = File.join(TMP_ROOT, PROJECT_NAME)
19
+ if defined?(APP_ROOT)
20
+ APP_ROOT.replace(app_root)
21
+ else
22
+ APP_ROOT = app_root
23
+ end
24
+ if defined?(RAILS_ROOT)
25
+ RAILS_ROOT.replace(app_root)
26
+ else
27
+ RAILS_ROOT = app_root
28
+ end
29
+
30
+ begin
31
+ require 'rubigen'
32
+ rescue LoadError
33
+ require 'rubygems'
34
+ require 'rubigen'
35
+ end
36
+ require 'rubigen/helpers/generator_test_helper'
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/invoicing_generator'
@@ -0,0 +1,46 @@
1
+ require File.join(File.dirname(__FILE__), "test_generator_helper.rb")
2
+
3
+ class TestInvoicingLedgerGenerator < Test::Unit::TestCase
4
+ include RubiGen::GeneratorTestHelper
5
+
6
+ def setup
7
+ bare_setup
8
+ Rails::Generator::Base.use_application_sources!
9
+ Rails::Generator::Scripts::Generate.new.run([APP_ROOT], :generator => 'app')
10
+ end
11
+
12
+ def teardown
13
+ bare_teardown
14
+ end
15
+
16
+ # Some generator-related assertions:
17
+ # assert_generated_file(name, &block) # block passed the file contents
18
+ # assert_directory_exists(name)
19
+ # assert_generated_class(name, &block)
20
+ # assert_generated_module(name, &block)
21
+ # assert_generated_test_for(name, &block)
22
+ # The assert_generated_(class|module|test_for) &block is passed the body of the class/module within the file
23
+ # assert_has_method(body, *methods) # check that the body has a list of methods (methods with parentheses not supported yet)
24
+ #
25
+ # Other helper methods are:
26
+ # app_root_files - put this in teardown to show files generated by the test method (e.g. p app_root_files)
27
+ # bare_setup - place this in setup method to create the APP_ROOT folder for each test
28
+ # bare_teardown - place this in teardown method to destroy the TMP_ROOT or APP_ROOT folder after each test
29
+
30
+ def test_generator_without_options
31
+ name = "myapp"
32
+ run_generator('invoicing_ledger', [name], sources)
33
+ assert_directory_exists "some_folder"
34
+ assert_generated_file "some_file_after_erb.rb"
35
+ end
36
+
37
+ private
38
+ def sources
39
+ [RubiGen::PathSource.new(:test, File.join(File.dirname(__FILE__),"..", generator_path))
40
+ ]
41
+ end
42
+
43
+ def generator_path
44
+ "rails_generators"
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: invoicing_generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Kleppmann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDQjCCAiqgAwIBAgIBADANBgkqhkiG9w0BAQUFADBHMRIwEAYDVQQDDAlydWJ5
14
+ Zm9yZ2UxHDAaBgoJkiaJk/IsZAEZFgxlcHRjb21wdXRpbmcxEzARBgoJkiaJk/Is
15
+ ZAEZFgNjb20wHhcNMDkwNDE0MTkwMTIwWhcNMTAwNDE0MTkwMTIwWjBHMRIwEAYD
16
+ VQQDDAlydWJ5Zm9yZ2UxHDAaBgoJkiaJk/IsZAEZFgxlcHRjb21wdXRpbmcxEzAR
17
+ BgoJkiaJk/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
18
+ AQDTglrdKabHepgLjgzM1Z52ABCZZ/xsBbn+4pE2jm7aGj2c0fZ+5Uhg0/MfyKsz
19
+ g3jEFjj0GeNFW7l1sHJYf8mTrdCyAuaymyB2LcLwPtte7/3daAWcs6wAJR8nm9xa
20
+ CzoeAFjCLcbhZazNBURMizj1z9eTArxhpfpNw4uSIExxNRoykeiFGZ4iq5Getj5x
21
+ B/JNTdxM7m2KLx+3YKp2LsV0NLL7hRp6zZ6KW1NTWt1mQ58SjDUiRhThfxPfVpCA
22
+ NI3O+ikDERJWo+nLMUNAZXiB6iMimgUNIUm462tbrumloEjQ/wJE6veGyCRS4jfq
23
+ Ldnuf6CKFRIxhb9QaN+cu0lLAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQD
24
+ AgSwMB0GA1UdDgQWBBRR5pYhCiPVxI3rYNDwFcCSqOUGOTANBgkqhkiG9w0BAQUF
25
+ AAOCAQEAnrM8+tf8f5y8icgcWErHTZZ6oInZxbH8DbAbJ9zIdD/u2o8agzykc/ub
26
+ Kza0RLJoINt0f1Bb6hzIja82EPeEEQKgR6BJAwPZlxZLGYBTyZeZRy3PJ8IjQ9Zk
27
+ Fl6OOjmxFfjgF0UGvFHPYUJaNtN8kPs2lyZYmmUrf7qF0n6nwShnVkYePUlvyW0i
28
+ kqloUNEB5PbHhEwmSTSYOseqm2l2rOAgN3aKVzNFWiMjzZn8OwYaETtD83yB9zlK
29
+ hqnkWqtTW1V1mEZRyNIx71QdrsaovPQhIKp0bMFUwntYXklVKqxYGHebwt//Gb++
30
+ jT4Qh3sYJbvqWGFAQcuOIf4spvpNiA==
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2009-04-20 00:00:00 +01:00
34
+ default_executable:
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: invoicing
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "="
43
+ - !ruby/object:Gem::Version
44
+ version: 0.2.0
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: newgem
48
+ type: :development
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.0
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: hoe
58
+ type: :development
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.8.0
65
+ version:
66
+ description: This is a framework for generating and displaying invoices (ideal for commercial Rails apps). It allows for flexible business logic; provides tools for tax handling, commission calculation etc. It aims to be both developer-friendly and accountant-friendly. The Ruby Invoicing Framework is based on {ActiveRecord}[http://api.rubyonrails.org/classes/ActiveRecord/Base.html]. Please see {the website}[http://ept.github.com/invoicing/] for an introduction to using Invoicing, and check the {API reference}[http://invoicing.rubyforge.org/doc/] for in-depth details.
67
+ email:
68
+ - rubyforge@eptcomputing.com
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ extra_rdoc_files:
74
+ - History.txt
75
+ - Manifest.txt
76
+ - PostInstall.txt
77
+ - README.rdoc
78
+ files:
79
+ - History.txt
80
+ - LICENSE
81
+ - Manifest.txt
82
+ - PostInstall.txt
83
+ - README.rdoc
84
+ - Rakefile
85
+ - lib/invoicing_generator.rb
86
+ - lib/invoicing_generator/generator_extensions.rb
87
+ - lib/invoicing_generator/name_tools.rb
88
+ - lib/invoicing_generator/option_tools.rb
89
+ - rails_generators/invoicing_ledger/USAGE
90
+ - rails_generators/invoicing_ledger/invoicing_ledger_generator.rb
91
+ - rails_generators/invoicing_ledger/templates/controller.rb
92
+ - rails_generators/invoicing_ledger/templates/credit_note.rb
93
+ - rails_generators/invoicing_ledger/templates/initializer.rb
94
+ - rails_generators/invoicing_ledger/templates/invoice.rb
95
+ - rails_generators/invoicing_ledger/templates/ledger_item.rb
96
+ - rails_generators/invoicing_ledger/templates/ledger_view.html
97
+ - rails_generators/invoicing_ledger/templates/line_item.rb
98
+ - rails_generators/invoicing_ledger/templates/migration.rb
99
+ - rails_generators/invoicing_ledger/templates/payment.rb
100
+ - rails_generators/invoicing_ledger/templates/statement_view.html
101
+ - rails_generators/invoicing_ledger/templates/stylesheet.css
102
+ - script/console
103
+ - script/destroy
104
+ - script/generate
105
+ - test/test_generator_helper.rb
106
+ - test/test_helper.rb
107
+ - test/test_invoicing_ledger_generator.rb
108
+ has_rdoc: true
109
+ homepage: "{Ruby Invoicing Framework website}[http://ept.github.com/invoicing/]"
110
+ post_install_message: PostInstall.txt
111
+ rdoc_options:
112
+ - --main
113
+ - README.rdoc
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: "0"
121
+ version:
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: "0"
127
+ version:
128
+ requirements: []
129
+
130
+ rubyforge_project: invoicing
131
+ rubygems_version: 1.3.1
132
+ signing_key:
133
+ specification_version: 2
134
+ summary: This is a framework for generating and displaying invoices (ideal for commercial Rails apps)
135
+ test_files:
136
+ - test/test_generator_helper.rb
137
+ - test/test_helper.rb
138
+ - test/test_invoicing_ledger_generator.rb
Binary file