invoice_creator 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +4 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.md +25 -0
- data/README.md +29 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/invoice_creator +4 -0
- data/bin/setup +8 -0
- data/config.yml +26 -0
- data/invoice_creator.gemspec +28 -0
- data/lib/invoice_creator.rb +8 -0
- data/lib/invoice_creator/cli.rb +45 -0
- data/lib/invoice_creator/config_reader.rb +33 -0
- data/lib/invoice_creator/models/invoice.rb +34 -0
- data/lib/invoice_creator/presenters/invoice.rb +62 -0
- data/lib/invoice_creator/services/invoice_printer.rb +67 -0
- data/lib/invoice_creator/version.rb +3 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4adede3f3b67b7489075f69ddb3c89ff5fd30bc923afaa1247f988c56dd019ed
|
4
|
+
data.tar.gz: 7b8e9aeadacb1fb330c39f3107bd32fde8af4bf294ab25b354242042a67ac7f0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 689c22c4f20833e887bbef7d94648356c94d5e5b9be9c0b6761a69797e550678f5f12c066d50ffd7bc17b9bd93f7f648af9a044985218bbcfbed5887d5973a39
|
7
|
+
data.tar.gz: 89bfbd8b8bcabb3e4ddb3c3877e013b8afffe6230148719169aefc941fb6749e94c353e04b8963c9f73c54e7a872fc367fd249a87b59713666d665f35f453d74
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at npufal@doximity.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: https://contributor-covenant.org
|
74
|
+
[version]: https://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
invoice_creator (0.1.0)
|
5
|
+
prawn (= 2.2.2)
|
6
|
+
prawn-table (= 0.2.2)
|
7
|
+
thor (= 0.20.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
diff-lcs (1.4.4)
|
13
|
+
pdf-core (0.7.0)
|
14
|
+
prawn (2.2.2)
|
15
|
+
pdf-core (~> 0.7.0)
|
16
|
+
ttfunk (~> 1.5)
|
17
|
+
prawn-table (0.2.2)
|
18
|
+
prawn (>= 1.3.0, < 3.0.0)
|
19
|
+
rake (12.3.3)
|
20
|
+
rspec (3.9.0)
|
21
|
+
rspec-core (~> 3.9.0)
|
22
|
+
rspec-expectations (~> 3.9.0)
|
23
|
+
rspec-mocks (~> 3.9.0)
|
24
|
+
rspec-core (3.9.3)
|
25
|
+
rspec-support (~> 3.9.3)
|
26
|
+
rspec-expectations (3.9.2)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.9.0)
|
29
|
+
rspec-mocks (3.9.1)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.9.0)
|
32
|
+
rspec-support (3.9.3)
|
33
|
+
thor (0.20.0)
|
34
|
+
ttfunk (1.6.2.1)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
invoice_creator!
|
41
|
+
rake (~> 12.0)
|
42
|
+
rspec (~> 3.0)
|
43
|
+
|
44
|
+
BUNDLED WITH
|
45
|
+
1.17.2
|
data/LICENSE.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Copyright © 2018 Nicholas Pufal
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person
|
7
|
+
obtaining a copy of this software and associated documentation
|
8
|
+
files (the “Software”), to deal in the Software without
|
9
|
+
restriction, including without limitation the rights to use,
|
10
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the
|
12
|
+
Software is furnished to do so, subject to the following
|
13
|
+
conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Invoice Creator
|
2
|
+
|
3
|
+
A simple invoice creation tool to help you bill your IT clients.
|
4
|
+
|
5
|
+
![Sample Invoice](https://user-images.githubusercontent.com/680151/47966699-92c76200-e03c-11e8-8b22-f4fa3e63ef75.png)
|
6
|
+
|
7
|
+
## Set up
|
8
|
+
|
9
|
+
The codebase has been converted into a Ruby gem so you can just install it with:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
gem install invoice_creator
|
13
|
+
```
|
14
|
+
|
15
|
+
...and the binary should be available to you globally 🎉
|
16
|
+
|
17
|
+
Just make sure to go into the gem's folder and edit the file `config.yml` so that it's tailored to
|
18
|
+
your needs - define your rate, date format, filename format, etc.
|
19
|
+
|
20
|
+
You can do `gem open invoice_creator` for quick access to the gem's folder.
|
21
|
+
|
22
|
+
## Usage example
|
23
|
+
|
24
|
+
Let's say we want to create an invoice that represents 168 billable hours and has
|
25
|
+
invoice number set to 10:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
./bin/invoice_creator create 168 --number 10
|
29
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "invoice_creator"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/invoice_creator
ADDED
data/bin/setup
ADDED
data/config.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
settings:
|
2
|
+
rate: 100.00
|
3
|
+
date_format: "%b %d, %Y"
|
4
|
+
currency_abbreviation: "USD"
|
5
|
+
currency_format: "$%.02f"
|
6
|
+
due_day: 10 # 10th of the current month
|
7
|
+
invoice_identifier: "INV-%04d"
|
8
|
+
filename: "invoice-%Y-%m-%d.pdf" # absolute or relative path
|
9
|
+
|
10
|
+
data:
|
11
|
+
from: |
|
12
|
+
John Smith
|
13
|
+
123 10th Ave
|
14
|
+
Fake City, SK, T2ZABC
|
15
|
+
Fake Country
|
16
|
+
to: |
|
17
|
+
Acme Inc.
|
18
|
+
123 1st St. Suite 001
|
19
|
+
Fake Country
|
20
|
+
12345 AZ
|
21
|
+
extra_info: |
|
22
|
+
<b>Payment information:</b>
|
23
|
+
Account Holder: John Smith
|
24
|
+
Account Number: 1234567
|
25
|
+
Transit number: 0909
|
26
|
+
Branch number: 9898
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'lib/invoice_creator/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "invoice_creator"
|
5
|
+
spec.version = InvoiceCreator::VERSION
|
6
|
+
spec.authors = ["Nicholas Pufal"]
|
7
|
+
spec.email = ["github@npufal.com"]
|
8
|
+
spec.summary = %q{A simple invoice creation tool to help you bill your tech clients.}
|
9
|
+
spec.homepage = "https://github.com/nicholaspufal/invoice_creator"
|
10
|
+
spec.license = "MIT"
|
11
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
12
|
+
|
13
|
+
# Specify which files should be added to the gem when it is released.
|
14
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
15
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
16
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
end
|
18
|
+
spec.bindir = "bin"
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "prawn", "2.2.2"
|
23
|
+
spec.add_runtime_dependency "prawn-table", "0.2.2"
|
24
|
+
spec.add_runtime_dependency "thor", "0.20.0"
|
25
|
+
|
26
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require "invoice_creator/version"
|
2
|
+
require "invoice_creator/config_reader"
|
3
|
+
require "invoice_creator/models/invoice"
|
4
|
+
require "invoice_creator/services/invoice_printer"
|
5
|
+
require "invoice_creator/presenters/invoice"
|
6
|
+
require "invoice_creator/cli"
|
7
|
+
|
8
|
+
module InvoiceCreator; end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module InvoiceCreator
|
4
|
+
class Cli < Thor
|
5
|
+
desc "create HOURS [EXPENSES_AMOUNT]", "Generates an invoice for the given amount of HOURS"
|
6
|
+
option :number, required: true
|
7
|
+
long_desc <<-LONGDESC
|
8
|
+
`./bin/invoice_generator create HOURS` will generate an invoice based on an amount of hours
|
9
|
+
of your choosing. Please update `config.yml` with your preferences before
|
10
|
+
running this command.
|
11
|
+
|
12
|
+
You can optionally specify a second parameter that represents an expenses
|
13
|
+
amount and which will be shown as part of a second row in your invoice.
|
14
|
+
|
15
|
+
Example:
|
16
|
+
> $ ./bin/invoice_generator create 168 450.25
|
17
|
+
|
18
|
+
A flag `--number` can also be used to define the invoice's number (the default is 1).
|
19
|
+
The actual number mask is defined within `config.yml`
|
20
|
+
|
21
|
+
> $ ./bin/invoice_generator create --number 25 168 450.25
|
22
|
+
LONGDESC
|
23
|
+
def create(hours, expenses_amount = 0.0)
|
24
|
+
invoice = Models::Invoice.new(
|
25
|
+
rate: ConfigReader.instance.rate,
|
26
|
+
due_day: ConfigReader.instance.due_day,
|
27
|
+
billable_hours: hours.to_f,
|
28
|
+
expenses_amount: expenses_amount.to_f,
|
29
|
+
number: options[:number]
|
30
|
+
)
|
31
|
+
|
32
|
+
presenter = Presenters::Invoice.new(
|
33
|
+
invoice: invoice,
|
34
|
+
config: ConfigReader.instance
|
35
|
+
)
|
36
|
+
|
37
|
+
Services::InvoicePrinter.new(presenter: presenter).print
|
38
|
+
|
39
|
+
puts <<~MESSAGE
|
40
|
+
Invoice created.
|
41
|
+
You can find it @ #{presenter.filename}
|
42
|
+
MESSAGE
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "ostruct"
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module InvoiceCreator
|
6
|
+
class ConfigReader
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@yaml = YAML.load_file("config.yml")
|
11
|
+
end
|
12
|
+
|
13
|
+
def settings
|
14
|
+
@settings ||= OpenStruct.new(@yaml["settings"])
|
15
|
+
end
|
16
|
+
|
17
|
+
def data
|
18
|
+
@data ||= OpenStruct.new(@yaml["data"])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Hacky way to avoid having to define a method for each of the config properties.
|
22
|
+
# Here just for fun and to make it easier to play around with the code.
|
23
|
+
# This causes undesireable downstream effects, i.e. calling `respond_to?(:anything)`
|
24
|
+
# would return true, which it's fine in this codebase/project
|
25
|
+
def method_missing(method, *args, &block)
|
26
|
+
settings.public_send(method) || data.public_send(method) || super
|
27
|
+
end
|
28
|
+
|
29
|
+
def respond_to_missing?(method_name, *args)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "date"
|
2
|
+
|
3
|
+
module InvoiceCreator
|
4
|
+
module Models
|
5
|
+
class Invoice
|
6
|
+
attr_reader :expenses_amount,
|
7
|
+
:billable_hours,
|
8
|
+
:invoice_date,
|
9
|
+
:rate,
|
10
|
+
:number
|
11
|
+
|
12
|
+
def initialize(rate:, due_day:, billable_hours:, expenses_amount: 0.0, invoice_date: Date.today, number: 1)
|
13
|
+
@rate = rate
|
14
|
+
@billable_hours = billable_hours
|
15
|
+
@expenses_amount = expenses_amount
|
16
|
+
@invoice_date = invoice_date
|
17
|
+
@due_day = due_day
|
18
|
+
@number = number
|
19
|
+
end
|
20
|
+
|
21
|
+
def due_date
|
22
|
+
Date.new(@invoice_date.year, @invoice_date.month, @due_day)
|
23
|
+
end
|
24
|
+
|
25
|
+
def total
|
26
|
+
billable_amount + @expenses_amount
|
27
|
+
end
|
28
|
+
|
29
|
+
def billable_amount
|
30
|
+
@billable_hours * @rate
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module InvoiceCreator
|
4
|
+
module Presenters
|
5
|
+
class Invoice
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def initialize(invoice:, config:)
|
9
|
+
@invoice = invoice
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def filename
|
14
|
+
@invoice.invoice_date.strftime(@config.filename)
|
15
|
+
end
|
16
|
+
|
17
|
+
def due_date
|
18
|
+
@invoice.due_date.strftime(@config.date_format)
|
19
|
+
end
|
20
|
+
|
21
|
+
def date
|
22
|
+
@invoice.invoice_date.strftime(@config.date_format)
|
23
|
+
end
|
24
|
+
|
25
|
+
def billable_amount
|
26
|
+
amount(@invoice.billable_amount)
|
27
|
+
end
|
28
|
+
|
29
|
+
def rate
|
30
|
+
amount(@invoice.rate)
|
31
|
+
end
|
32
|
+
|
33
|
+
def invoice_identifier
|
34
|
+
sprintf(@config.invoice_identifier, @invoice.number)
|
35
|
+
end
|
36
|
+
|
37
|
+
def expenses_amount
|
38
|
+
amount(@invoice.expenses_amount)
|
39
|
+
end
|
40
|
+
|
41
|
+
def has_expenses?
|
42
|
+
@invoice.expenses_amount > 0
|
43
|
+
end
|
44
|
+
|
45
|
+
def total
|
46
|
+
amount(@invoice.total)
|
47
|
+
end
|
48
|
+
|
49
|
+
def_delegators :@invoice, :billable_hours
|
50
|
+
def_delegators :@config, :to
|
51
|
+
def_delegators :@config, :from
|
52
|
+
def_delegators :@config, :extra_info
|
53
|
+
def_delegators :@config, :currency_abbreviation
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def amount(amount)
|
58
|
+
sprintf(@config.currency_format, amount)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "prawn"
|
2
|
+
require "prawn/table"
|
3
|
+
|
4
|
+
module InvoiceCreator
|
5
|
+
module Services
|
6
|
+
class InvoicePrinter
|
7
|
+
def initialize(presenter:)
|
8
|
+
@presenter = presenter
|
9
|
+
@prawn = Prawn::Document.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def print
|
13
|
+
@prawn.define_grid(:columns => 5, :rows => 8, :gutter => 10)
|
14
|
+
|
15
|
+
@prawn.grid([0,3], [0,4]).bounding_box do
|
16
|
+
@prawn.text "<b>INVOICE</b>", size: 30, align: :right, inline_format: true
|
17
|
+
end
|
18
|
+
|
19
|
+
@prawn.grid([1,3], [1,4]).bounding_box do
|
20
|
+
@prawn.text "<b>Invoice#</b> #{@presenter.invoice_identifier}", align: :right, inline_format: true
|
21
|
+
@prawn.move_down 5
|
22
|
+
@prawn.text "<b>Invoice Date</b> #{@presenter.date}", align: :right, inline_format: true
|
23
|
+
@prawn.move_down 5
|
24
|
+
@prawn.text "<b>Due Date</b> #{@presenter.due_date}", align: :right, inline_format: true
|
25
|
+
end
|
26
|
+
|
27
|
+
@prawn.grid([0,0], [0,2]).bounding_box do
|
28
|
+
@prawn.text "<b>From</b>", align: :left, inline_format: true
|
29
|
+
@prawn.text @presenter.from
|
30
|
+
end
|
31
|
+
|
32
|
+
@prawn.grid([1,0], [1,2]).bounding_box do
|
33
|
+
@prawn.text "<b>To</b>", align: :left, inline_format: true
|
34
|
+
@prawn.text @presenter.to
|
35
|
+
end
|
36
|
+
|
37
|
+
@prawn.table([%w[Item HRS/QTY Rate Amount], *rows], row_colors: ["F0F0F0", "FFFFFF"], width: 550)
|
38
|
+
|
39
|
+
@prawn.move_down 20
|
40
|
+
@prawn.text "<b>Total (#{@presenter.currency_abbreviation}) #{@presenter.total}</b>", align: :right, inline_format: true
|
41
|
+
@prawn.move_down 20
|
42
|
+
@prawn.stroke_horizontal_rule
|
43
|
+
@prawn.move_down 20
|
44
|
+
|
45
|
+
@prawn.text @presenter.extra_info, inline_format: true
|
46
|
+
|
47
|
+
@prawn.render_file @presenter.filename
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def rows
|
53
|
+
rows = []
|
54
|
+
|
55
|
+
rows << Array(
|
56
|
+
["Software Development", @presenter.billable_hours, @presenter.rate, @presenter.billable_amount]
|
57
|
+
)
|
58
|
+
|
59
|
+
if @presenter.has_expenses?
|
60
|
+
rows << Array(["Expenses", 1, @presenter.expenses_amount, @presenter.expenses_amount])
|
61
|
+
end
|
62
|
+
|
63
|
+
rows
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: invoice_creator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Pufal
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: prawn
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: prawn-table
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.2.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.2.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.20.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.20.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '12.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '12.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- github@npufal.com
|
86
|
+
executables:
|
87
|
+
- console
|
88
|
+
- invoice_creator
|
89
|
+
- setup
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- ".gitignore"
|
94
|
+
- ".rspec"
|
95
|
+
- ".travis.yml"
|
96
|
+
- CHANGELOG.md
|
97
|
+
- CODE_OF_CONDUCT.md
|
98
|
+
- Gemfile
|
99
|
+
- Gemfile.lock
|
100
|
+
- LICENSE.md
|
101
|
+
- README.md
|
102
|
+
- Rakefile
|
103
|
+
- bin/console
|
104
|
+
- bin/invoice_creator
|
105
|
+
- bin/setup
|
106
|
+
- config.yml
|
107
|
+
- invoice_creator.gemspec
|
108
|
+
- lib/invoice_creator.rb
|
109
|
+
- lib/invoice_creator/cli.rb
|
110
|
+
- lib/invoice_creator/config_reader.rb
|
111
|
+
- lib/invoice_creator/models/invoice.rb
|
112
|
+
- lib/invoice_creator/presenters/invoice.rb
|
113
|
+
- lib/invoice_creator/services/invoice_printer.rb
|
114
|
+
- lib/invoice_creator/version.rb
|
115
|
+
homepage: https://github.com/nicholaspufal/invoice_creator
|
116
|
+
licenses:
|
117
|
+
- MIT
|
118
|
+
metadata:
|
119
|
+
homepage_uri: https://github.com/nicholaspufal/invoice_creator
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubygems_version: 3.0.3
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: A simple invoice creation tool to help you bill your tech clients.
|
139
|
+
test_files: []
|