receipts 1.1.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
- require "open-uri"
4
+ require "rake/testtask"
4
5
 
5
- RSpec::Core::RakeTask.new("spec")
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
6
11
 
7
- # If you want to make this the default task
8
- task default: :spec
9
- task test: :spec
12
+ task default: :test
10
13
 
11
14
  task :console do
12
15
  exec "irb -r receipts -I ./lib"
@@ -14,60 +17,74 @@ end
14
17
 
15
18
  task :examples do
16
19
  [:receipt, :invoice, :statement].each { |t| Rake::Task[t].invoke }
17
-
18
20
  puts "Use `open examples` to view example PDFs."
19
21
  end
20
22
 
21
23
  task :receipt do
22
24
  require "./lib/receipts"
23
25
 
24
- Receipts::Receipt.new(
25
- id: "123",
26
- subheading: "RECEIPT FOR CHARGE #1",
27
- product: "GoRails",
26
+ r = Receipts::Receipt.new(
27
+ recipient: [
28
+ "<b>Bill To</b>",
29
+ "Customer",
30
+ "Address",
31
+ "City, State Zipcode",
32
+ "customer@example.org"
33
+ ],
28
34
  company: {
29
- name: "GoRails, LLC",
35
+ name: "Example, LLC",
30
36
  address: "123 Fake Street\nNew York City, NY 10012",
37
+ phone: "(555) 867-5309",
31
38
  email: "support@example.com",
32
- logo: "https://www.ruby-lang.org/images/header-ruby-logo@2x.png"
39
+ logo: File.expand_path("./examples/images/logo.png")
33
40
  },
41
+ details: [
42
+ ["Receipt Number", "123"],
43
+ ["Date paid", Date.today.strftime("%B %d, %Y")],
44
+ ["Payment method", "ACH super long super long super long super long super long"]
45
+ ],
34
46
  line_items: [
35
- ["Date", Time.now.to_s],
36
- ["Account Billed", "Example User (user@example.com)"],
37
- ["Product", "GoRails"],
38
- ["Amount", "$19.00"],
39
- ["Charged to", "Visa (**** **** **** 1234)"],
40
- ["Transaction ID", "123456"]
47
+ ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
48
+ ["Subscription", "$19.00", "1", "$19.00"],
49
+ [nil, nil, "Subtotal", "$19.00"],
50
+ [nil, nil, "Tax", "$1.12"],
51
+ [nil, nil, "Total", "$20.12"],
52
+ [nil, nil, "<b>Amount paid</b>", "$20.12"],
53
+ [nil, nil, "Refunded on #{Date.today.strftime("%B %d, %Y")}", "$5.00"]
41
54
  ]
42
- ).render_file "examples/receipt.pdf"
55
+ )
56
+ r.render_file "examples/receipt.pdf"
43
57
  end
44
58
 
45
59
  task :invoice do
46
60
  require "./lib/receipts"
47
61
 
48
62
  Receipts::Invoice.new(
49
- id: "123",
50
- issue_date: Date.today,
51
- due_date: Date.today + 30,
52
- status: "<b><color rgb='#5eba7d'>PAID</color></b>",
53
- bill_to: [
54
- "GoRails, LLC",
63
+ details: [
64
+ ["Invoice Number", "123"],
65
+ ["Issue Date", Date.today.strftime("%B %d, %Y")],
66
+ ["Due Date", Date.today.strftime("%B %d, %Y")],
67
+ ["Status", "<b><color rgb='#5eba7d'>PAID</color></b>"]
68
+ ],
69
+ recipient: [
70
+ "<b>Bill To</b>",
71
+ "Customer",
55
72
  "Address",
56
73
  "City, State Zipcode",
57
- nil,
58
- "mail@example.com"
74
+ "customer@example.org"
59
75
  ],
60
76
  company: {
61
- name: "GoRails, LLC",
77
+ name: "Example, LLC",
62
78
  address: "123 Fake Street\nNew York City, NY 10012",
79
+ phone: "(555) 867-5309",
63
80
  email: "support@example.com",
64
- # logo: Rails.root.join("app/assets/images/gorails.png")
65
- # logo: File.expand_path("./examples/gorails.png")
66
- logo: File.open("./examples/gorails.png")
81
+ # logo: Rails.root.join("app/assets/images/logo.png")
82
+ # logo: File.open("./examples/images/logo.png")
83
+ logo: File.expand_path("./examples/images/logo.png")
67
84
  },
68
85
  line_items: [
69
86
  ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
70
- ["GoRails Subscription", "$19.00", "1", "$19.00"],
87
+ ["Subscription", "$19.00", "1", "$19.00"],
71
88
  [nil, nil, "Subtotal", "$19.00"],
72
89
  [nil, nil, "Tax Rate", "0%"],
73
90
  [nil, nil, "Amount Due", "$19.00"]
@@ -79,26 +96,28 @@ task :statement do
79
96
  require "./lib/receipts"
80
97
 
81
98
  Receipts::Statement.new(
82
- id: "123",
83
- issue_date: Date.today,
84
- start_date: Date.today - 30,
85
- end_date: Date.today,
86
- bill_to: [
87
- "GoRails, LLC",
88
- "123 Fake Street",
89
- "New York City, NY 10012",
90
- nil,
91
- "mail@example.com"
99
+ details: [
100
+ ["Statement Number", "123"],
101
+ ["Issue Date", Date.today.strftime("%B %d, %Y")],
102
+ ["Period", "#{(Date.today - 30).strftime("%B %d, %Y")} - #{Date.today.strftime("%B %d, %Y")}"]
103
+ ],
104
+ recipient: [
105
+ "<b>Bill To</b>",
106
+ "Customer",
107
+ "Address",
108
+ "City, State Zipcode",
109
+ "customer@example.org"
92
110
  ],
93
111
  company: {
94
- name: "GoRails, LLC",
112
+ name: "Example, LLC",
95
113
  address: "123 Fake Street\nNew York City, NY 10012",
96
114
  email: "support@example.com",
97
- logo: File.expand_path("./examples/gorails.png")
115
+ phone: "(555) 867-5309",
116
+ logo: File.expand_path("./examples/images/logo.png")
98
117
  },
99
118
  line_items: [
100
119
  ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
101
- ["GoRails Subscription", "$19.00", "1", "$19.00"],
120
+ ["Subscription", "$19.00", "1", "$19.00"],
102
121
  [nil, nil, "Subtotal", "$19.00"],
103
122
  [nil, nil, "Tax Rate", "0%"],
104
123
  [nil, nil, "Total", "$19.00"]
File without changes
Binary file
data/examples/invoice.pdf CHANGED
Binary file
data/examples/receipt.pdf CHANGED
Binary file
Binary file
@@ -0,0 +1,102 @@
1
+ module Receipts
2
+ class Base < Prawn::Document
3
+ attr_accessor :title, :company
4
+
5
+ class << self
6
+ attr_reader :title
7
+ end
8
+
9
+ def initialize(attributes = {})
10
+ super(page_size: "LETTER")
11
+ setup_fonts attributes.fetch(:font, Receipts.default_font)
12
+
13
+ @title = attributes.fetch(:title, self.class.title)
14
+
15
+ generate_from(attributes)
16
+ end
17
+
18
+ def generate_from(attributes)
19
+ return if attributes.empty?
20
+
21
+ company = attributes.fetch(:company)
22
+ header company: company
23
+ render_details attributes.fetch(:details)
24
+ render_billing_details company: company, recipient: attributes.fetch(:recipient)
25
+ render_line_items attributes.fetch(:line_items)
26
+ render_footer attributes.fetch(:footer, default_message(company: company))
27
+ end
28
+
29
+ def setup_fonts(custom_font = nil)
30
+ if !!custom_font
31
+ font_families.update "Primary" => custom_font
32
+ font "Primary"
33
+ end
34
+
35
+ font_size 8
36
+ end
37
+
38
+ def load_image(logo)
39
+ if logo.is_a? String
40
+ logo.start_with?("http") ? URI.parse(logo).open : File.open(logo)
41
+ else
42
+ logo
43
+ end
44
+ end
45
+
46
+ def header(company: {}, height: 16)
47
+ logo = company[:logo]
48
+
49
+ if logo.nil?
50
+ text company.fetch(:name), align: :right, style: :bold, size: 16, color: "4b5563"
51
+ else
52
+ image load_image(logo), height: height, position: :right
53
+ end
54
+
55
+ move_up height
56
+ text title, style: :bold, size: 16
57
+ end
58
+
59
+ def render_details(details, margin_top: 16)
60
+ move_down margin_top
61
+ table(details, cell_style: {borders: [], inline_format: true, padding: [0, 8, 2, 0]})
62
+ end
63
+
64
+ def render_billing_details(company:, recipient:, margin_top: 16)
65
+ move_down margin_top
66
+
67
+ company_details = [
68
+ company[:address],
69
+ company[:phone],
70
+ company[:email]
71
+ ].compact.join("\n")
72
+
73
+ line_items = [
74
+ [
75
+ {content: "<b>#{company.fetch(:name)}</b>\n#{company_details}", padding: [0, 12, 0, 0]},
76
+ {content: Array(recipient).join("\n"), padding: [0, 12, 0, 0]}
77
+ ]
78
+ ]
79
+ table(line_items, width: bounds.width, cell_style: {borders: [], inline_format: true, overflow: :expand})
80
+ end
81
+
82
+ def render_line_items(line_items, margin_top: 30)
83
+ move_down margin_top
84
+
85
+ borders = line_items.length - 2
86
+ table(line_items, width: bounds.width, cell_style: {border_color: "eeeeee", inline_format: true}) do
87
+ cells.padding = 6
88
+ cells.borders = []
89
+ row(0..borders).borders = [:bottom]
90
+ end
91
+ end
92
+
93
+ def render_footer(message, margin_top: 30)
94
+ move_down margin_top
95
+ text message, inline_format: true
96
+ end
97
+
98
+ def default_message(company:)
99
+ "For questions, contact us anytime at <color rgb='326d92'><link href='mailto:#{company.fetch(:email)}?subject=Question about my receipt'><b>#{company.fetch(:email)}</b></link></color>."
100
+ end
101
+ end
102
+ end
@@ -1,91 +1,5 @@
1
- require "prawn"
2
- require "prawn/table"
3
-
4
1
  module Receipts
5
2
  class Invoice < Base
6
- attr_reader :attributes, :id, :company, :custom_font, :line_items, :logo, :message, :product, :subheading, :bill_to, :issue_date, :due_date, :status
7
-
8
- def initialize(attributes)
9
- @attributes = attributes
10
- @id = attributes.fetch(:id)
11
- @company = attributes.fetch(:company)
12
- @line_items = attributes.fetch(:line_items)
13
- @custom_font = attributes.fetch(:font, {})
14
- @message = attributes.fetch(:message) { default_message }
15
- @subheading = attributes.fetch(:subheading) { default_subheading }
16
- @bill_to = Array(attributes.fetch(:bill_to)).join("\n")
17
- @issue_date = attributes.fetch(:issue_date)
18
- @due_date = attributes.fetch(:due_date)
19
- @status = attributes.fetch(:status)
20
-
21
- super(page_size: "LETTER")
22
-
23
- setup_fonts if custom_font.any?
24
- generate
25
- end
26
-
27
- private
28
-
29
- def default_message
30
- "For questions, contact us anytime at <color rgb='326d92'><link href='mailto:#{company.fetch(:email)}?subject=Charge ##{id}'><b>#{company.fetch(:email)}</b></link></color>."
31
- end
32
-
33
- def default_subheading
34
- "INVOICE #%{id}"
35
- end
36
-
37
- def generate
38
- header
39
- description
40
- invoice_details
41
- charge_details
42
- footer
43
- end
44
-
45
- def header(height: 24)
46
- logo = company[:logo]
47
- return if logo.nil?
48
- image load_image(logo), height: height
49
- end
50
-
51
- def description
52
- move_down 8
53
- text label(subheading % {id: id}), inline_format: true, leading: 4
54
- end
55
-
56
- def invoice_details
57
- move_down 10
58
- font_size 9
59
-
60
- line_items = [
61
- [{content: "#{label("BILL TO")}\n#{bill_to}", rowspan: 3, padding: [0, 12, 0, 0]}, "#{label("INVOICE DATE")}\n#{issue_date}"],
62
- ["#{label("DUE DATE")}\n#{due_date}"],
63
- ["#{label("STATUS")}\n#{status}"]
64
- ]
65
- table(line_items, width: bounds.width, cell_style: {inline_format: true, overflow: :shrink_to_fit}) do
66
- cells.borders = []
67
- end
68
- end
69
-
70
- def charge_details
71
- move_down 30
72
-
73
- borders = line_items.length - 2
74
-
75
- table(line_items, width: bounds.width, cell_style: {border_color: "cccccc", inline_format: true, overflow: :shrink_to_fit}) do
76
- cells.padding = 10
77
- cells.borders = []
78
- row(0..borders).borders = [:bottom]
79
- end
80
- end
81
-
82
- def footer
83
- move_down 30
84
- text message, inline_format: true, leading: 4
85
-
86
- move_down 30
87
- text company.fetch(:name), inline_format: true
88
- text "<color rgb='888888'>#{company.fetch(:address)}</color>", inline_format: true
89
- end
3
+ @title = "Invoice"
90
4
  end
91
5
  end
@@ -1,70 +1,5 @@
1
1
  module Receipts
2
2
  class Receipt < Base
3
- attr_reader :attributes, :id, :company, :custom_font, :line_items, :logo, :message, :product, :subheading
4
-
5
- def initialize(attributes)
6
- @attributes = attributes
7
- @id = attributes.fetch(:id)
8
- @company = attributes.fetch(:company)
9
- @line_items = attributes.fetch(:line_items)
10
- @custom_font = attributes.fetch(:font, {})
11
- @message = attributes.fetch(:message) { default_message }
12
- @subheading = attributes.fetch(:subheading) { default_subheading }
13
-
14
- super(page_size: "LETTER")
15
-
16
- setup_fonts if custom_font.any?
17
- generate
18
- end
19
-
20
- private
21
-
22
- def default_message
23
- "We've received your payment for #{attributes.fetch(:product)}. You can keep this receipt for your records. For questions, contact us anytime at <color rgb='326d92'><link href='mailto:#{company.fetch(:email)}?subject=Charge ##{id}'><b>#{company.fetch(:email)}</b></link></color>."
24
- end
25
-
26
- def default_subheading
27
- "RECEIPT FOR CHARGE #%{id}"
28
- end
29
-
30
- def generate
31
- header
32
- description
33
- charge_details
34
- footer
35
- end
36
-
37
- def header(height: 24)
38
- logo = company[:logo]
39
- return if logo.nil?
40
- image load_image(logo), height: height
41
- end
42
-
43
- def description
44
- move_down 8
45
- text "<color rgb='a6a6a6'>#{subheading % {id: id}}</color>", inline_format: true
46
-
47
- move_down 30
48
- text message, inline_format: true, leading: 4
49
- end
50
-
51
- def charge_details
52
- move_down 30
53
- font_size 9
54
-
55
- borders = line_items.length - 2
56
-
57
- table(line_items, width: bounds.width, cell_style: {border_color: "cccccc", inline_format: true}) do
58
- cells.padding = 10
59
- cells.borders = []
60
- row(0..borders).borders = [:bottom]
61
- end
62
- end
63
-
64
- def footer
65
- move_down 45
66
- text company.fetch(:name), inline_format: true
67
- text "<color rgb='888888'>#{company.fetch(:address)}</color>", inline_format: true
68
- end
3
+ @title = "Receipt"
69
4
  end
70
5
  end
@@ -1,88 +1,5 @@
1
1
  module Receipts
2
2
  class Statement < Base
3
- attr_reader :attributes, :id, :company, :custom_font, :line_items, :logo, :message, :product, :subheading, :bill_to, :issue_date, :start_date, :end_date
4
-
5
- def initialize(attributes)
6
- @attributes = attributes
7
- @id = attributes.fetch(:id)
8
- @company = attributes.fetch(:company)
9
- @line_items = attributes.fetch(:line_items)
10
- @custom_font = attributes.fetch(:font, {})
11
- @message = attributes.fetch(:message) { default_message }
12
- @subheading = attributes.fetch(:subheading) { default_subheading }
13
- @bill_to = Array(attributes.fetch(:bill_to)).join("\n")
14
- @issue_date = attributes.fetch(:issue_date)
15
- @start_date = attributes.fetch(:start_date)
16
- @end_date = attributes.fetch(:end_date)
17
-
18
- super(page_size: "LETTER")
19
-
20
- setup_fonts if custom_font.any?
21
- generate
22
- end
23
-
24
- private
25
-
26
- def default_message
27
- "For questions, contact us anytime at <color rgb='326d92'><link href='mailto:#{company.fetch(:email)}?subject=Charge ##{id}'><b>#{company.fetch(:email)}</b></link></color>."
28
- end
29
-
30
- def default_subheading
31
- "STATEMENT #%{id}"
32
- end
33
-
34
- def generate
35
- header
36
- description
37
- statement_details
38
- charge_details
39
- footer
40
- end
41
-
42
- def header(height: 24)
43
- logo = company[:logo]
44
- return if logo.nil?
45
- image load_image(logo), height: height
46
- end
47
-
48
- def description
49
- move_down 8
50
- text label(subheading % {id: id}), inline_format: true, leading: 4
51
- end
52
-
53
- def statement_details
54
- move_down 10
55
- font_size 9
56
-
57
- line_items = [
58
- [{content: "#{label("BILL TO")}\n#{bill_to}", rowspan: 3, padding: [0, 12, 0, 0]}, "#{label("INVOICE DATE")}\n#{issue_date}"],
59
- ["#{label("STATEMENT DATE")}\n#{issue_date}"],
60
- ["#{label("STATEMENT PERIOD")}\n#{start_date} - #{end_date}"]
61
- ]
62
- table(line_items, width: bounds.width, cell_style: {inline_format: true, overflow: :shrink_to_fit}) do
63
- cells.borders = []
64
- end
65
- end
66
-
67
- def charge_details
68
- move_down 30
69
-
70
- borders = line_items.length - 2
71
-
72
- table(line_items, width: bounds.width, cell_style: {border_color: "cccccc", inline_format: true}) do
73
- cells.padding = 10
74
- cells.borders = []
75
- row(0..borders).borders = [:bottom]
76
- end
77
- end
78
-
79
- def footer
80
- move_down 30
81
- text message, inline_format: true, leading: 4
82
-
83
- move_down 30
84
- text company.fetch(:name), inline_format: true
85
- text "<color rgb='888888'>#{company.fetch(:address)}</color>", inline_format: true
86
- end
3
+ @title = "Statement"
87
4
  end
88
5
  end
@@ -1,3 +1,3 @@
1
1
  module Receipts
2
- VERSION = "1.1.2"
2
+ VERSION = "2.1.0"
3
3
  end
data/lib/receipts.rb CHANGED
@@ -4,26 +4,23 @@ require "prawn"
4
4
  require "prawn/table"
5
5
 
6
6
  module Receipts
7
+ autoload :Base, "receipts/base"
7
8
  autoload :Invoice, "receipts/invoice"
8
9
  autoload :Receipt, "receipts/receipt"
9
10
  autoload :Statement, "receipts/statement"
10
11
 
11
- class Base < Prawn::Document
12
- def setup_fonts
13
- font_families.update "Primary" => custom_font
14
- font "Primary"
15
- end
12
+ @@default_font = nil
16
13
 
17
- def load_image(logo)
18
- if logo.is_a? String
19
- logo.start_with?("http") ? URI.parse(logo).open : File.open(logo)
20
- else
21
- logo
22
- end
23
- end
14
+ # Customize the default font hash
15
+ # default_font = {
16
+ # bold: "path/to/font",
17
+ # normal: "path/to/font",
18
+ # }
19
+ def self.default_font=(path)
20
+ @@default_font = path
21
+ end
24
22
 
25
- def label(text)
26
- "<font size='8'><color rgb='a6a6a6'>#{text}</color></font>"
27
- end
23
+ def self.default_font
24
+ @@default_font
28
25
  end
29
26
  end
data/receipts.gemspec CHANGED
@@ -1,27 +1,32 @@
1
- lib = File.expand_path("../lib", __FILE__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require "receipts/version"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/receipts/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "receipts"
7
7
  spec.version = Receipts::VERSION
8
8
  spec.authors = ["Chris Oliver"]
9
9
  spec.email = ["excid3@gmail.com"]
10
+
10
11
  spec.summary = "Receipts for your Rails application that works with any payment provider."
11
12
  spec.description = "Receipts for your Rails application that works with any payment provider."
12
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/excid3/receipts"
13
14
  spec.license = "MIT"
14
15
 
15
- spec.files = `git ls-files -z`.split("\x0")
16
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib"]
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata["changelog_uri"] = "https://github.com/excid3/receipts/blob/master/CHANGELOG.md"
19
19
 
20
- spec.add_development_dependency "bundler"
21
- spec.add_development_dependency "rake", "~> 10.0"
22
- spec.add_development_dependency "rspec"
23
- spec.add_development_dependency "pry"
24
- spec.add_development_dependency "standard"
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ end
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
25
30
 
26
31
  spec.add_dependency "prawn", ">= 1.3.0", "< 3.0.0"
27
32
  spec.add_dependency "prawn-table", "~> 0.2.1"