receipts 1.1.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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"