receipts 1.1.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fead98b1a43ff6d6c86b13f9c8114ebcfa322b809f9f2b068b80e03370c63f65
4
- data.tar.gz: e7e29ceceac61563c182626d3d47ab697584e67896aff884097bb955236d44ca
3
+ metadata.gz: a0b0deba0350c50dd06db780729513d9c65d020c9d625b3c61c174078738ef44
4
+ data.tar.gz: 6b508e3232031df8d6952b9c2da80d5910022b2b53ba29e54f84080c12d522da
5
5
  SHA512:
6
- metadata.gz: de764a9d7466e6680243ac5b2f033534a6140048f99eb5bc15aaad5b38d27063e4ed7e70f2d45167064dec7b3f941d34b0cab29aab1977e876c926ded6e80839
7
- data.tar.gz: 7da1873655534b34d80bb735b8fe80da1d84d6f0618f1d1c7be35991e2d5ffeb197aa4b07390a3ba3aba4317ef42c7a874756b075213422d164ed296b9bb7a2b
6
+ metadata.gz: f734ad542b0405e91370fd960ab93283bd493cdd0523900b6f97a26f91bc8a57834512c7778c551af55e1208c232020743d39b73428bafe118679439838479f0
7
+ data.tar.gz: baca857094d744fa1ff47617940a9a665df5fc7da11ebc25e4ac180b9a324b1f00f82f85cfbba09952708e596cbdbe425d73abfab4371f319e7882e3d8dac59e
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  ### Unreleased
2
2
 
3
- ### 1.2.0
3
+ ### 2.1.0
4
+
5
+ * Add `Receipts.default_font` - @excid3
6
+
7
+ ### 2.0.0
8
+
9
+ * New, consistent layouts between Receipts, Invoices, and Statements - @excid3
10
+ * PDFs can now be completely customized - @excid3
11
+ * Add line_items to Receipts - @excid3
12
+
13
+ ### 1.1.2
4
14
 
5
15
  * Update design to give more room for longer product names, addresses, etc - @excid3
6
16
 
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in receipts.gemspec
4
4
  gemspec
5
+
6
+ gem "minitest", "~> 5.0"
7
+ gem "rake", "~> 13.0"
8
+ gem "standard"
9
+ gem "matrix", "~> 0.4"
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  ![travisci](https://api.travis-ci.org/excid3/receipts.svg)
2
2
 
3
- # Receipts
3
+ # Receipts Gem
4
4
 
5
- Receipts for your Rails application that works with any payment provider.
5
+ Receipts, Invoices, and Statements for your Rails application that works with any payment provider. Receipts uses Prawn to generate the PDFs.
6
6
 
7
- Check out the [example receipt](https://github.com/excid3/receipts/blob/master/examples/receipt.pdf?raw=true) and [example invoice](https://github.com/excid3/receipts/blob/master/examples/invoice.pdf?raw=true) PDFs.
7
+ Check out the [example PDFs](https://github.com/excid3/receipts/blob/master/examples/).
8
8
 
9
9
  ## Installation
10
10
 
@@ -24,112 +24,111 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
- Adding receipts to your application is pretty simple. All you need is a
28
- model that stores your transaction details. In this example our
29
- application has a model named `Charge` that we will use.
27
+ To generate a Receipt, Invoice, or Statement, create an instance and provide content to render:
30
28
 
31
- We're going to add a method called `receipt` on our model called `Charge`
32
- that will create a new receipt for the charge using attributes from the
33
- model.
29
+ ```ruby
30
+ r = Receipts::Receipt.new(
31
+ details: [
32
+ ["Receipt Number", "123"],
33
+ ["Date paid", Date.today],
34
+ ["Payment method", "ACH super long super long super long super long super long"]
35
+ ],
36
+ company: {
37
+ name: "Example, LLC",
38
+ address: "123 Fake Street\nNew York City, NY 10012",
39
+ email: "support@example.com",
40
+ logo: File.expand_path("./examples/images/logo.png")
41
+ },
42
+ recipient: [
43
+ "Customer",
44
+ "Their Address",
45
+ "City, State Zipcode",
46
+ nil,
47
+ "customer@example.org"
48
+ ],
49
+ line_items: [
50
+ ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
51
+ ["Subscription", "$19.00", "1", "$19.00"],
52
+ [nil, nil, "Subtotal", "$19.00"],
53
+ [nil, nil, "Tax", "$1.12"],
54
+ [nil, nil, "Total", "$20.12"],
55
+ [nil, nil, "<b>Amount paid</b>", "$20.12"],
56
+ [nil, nil, "Refunded on #{Date.today}", "$5.00"]
57
+ ],
58
+ footer: "Thanks for your business. Please contact us if you have any questions."
59
+ )
60
+
61
+ # Returns a string of the raw PDF
62
+ r.render
63
+
64
+ # Writes the PDF to disk
65
+ r.render_file "examples/receipt.pdf"
66
+ ```
67
+
68
+ ### Configuration
34
69
 
35
- Video Tutorial:
36
- [GoRails Episode #51](https://gorails.com/episodes/pdf-receipts)
70
+ You can specify the default font for all PDFs by defining the following in an initializer:
37
71
 
38
72
  ```ruby
39
- # == Schema Information
40
- #
41
- # Table name: charges
42
- #
43
- # id :integer not null, primary key
44
- # user_id :integer
45
- # stripe_id :string(255)
46
- # amount :integer
47
- # card_last4 :string(255)
48
- # card_type :string(255)
49
- # card_exp_month :integer
50
- # card_exp_year :integer
51
- # uuid :string
52
- # created_at :datetime
53
- # updated_at :datetime
54
- #
55
-
56
- class Charge < ActiveRecord::Base
57
- belongs_to :user
58
- validates :stripe_id, uniqueness: true
59
-
60
- def receipt
61
- Receipts::Receipt.new(
62
- id: id,
63
- subheading: "RECEIPT FOR CHARGE #%{id}",
64
- product: "GoRails",
65
- company: {
66
- name: "GoRails, LLC.",
67
- address: "123 Fake Street\nNew York City, NY 10012",
68
- email: "support@example.com",
69
- logo: Rails.root.join("app/assets/images/logo.png")
70
- },
71
- line_items: [
72
- ["Date", created_at.to_s],
73
- ["Account Billed", "#{user.name} (#{user.email})"],
74
- ["Product", "GoRails"],
75
- ["Amount", "$#{amount / 100}.00"],
76
- ["Charged to", "#{card_type} (**** **** **** #{card_last4})"],
77
- ["Transaction ID", uuid]
78
- ],
79
- font: {
80
- bold: Rails.root.join('app/assets/fonts/tradegothic/TradeGothic-Bold.ttf'),
81
- normal: Rails.root.join('app/assets/fonts/tradegothic/TradeGothic.ttf'),
82
- }
83
- )
84
- end
85
- end
73
+ Receipts.default_font = {
74
+ bold: Rails.root.join('app/assets/fonts/tradegothic/TradeGothic-Bold.ttf'),
75
+ normal: Rails.root.join('app/assets/fonts/tradegothic/TradeGothic.ttf'),
76
+ }
86
77
  ```
87
78
 
88
- Update the options for the receipt according to the data you want to
89
- display.
90
79
 
91
- ## Customizing Your Receipts
80
+ ### Options
92
81
 
93
- * `id` - **Required**
82
+ You can pass the following options to generate a PDF:
94
83
 
95
- This sets the ID of the charge on the receipt
84
+ * `recipient` - Array of customer details to include. Typically, this is name, address, email, VAT ID, etc.
96
85
 
97
- * `product` or `message` - **Required**
86
+ * `company` - Hash of your company details
98
87
 
99
- You can set either the product or message options. If you set product, it will use the default message. If you want a custom message, you can set the message option to populate it with custom text.
88
+ * `name` - Company name
100
89
 
101
- * `company` - **Required**
90
+ * `address` - Company address
102
91
 
103
- Company consists of several required nested attributes.
92
+ * `email` - Company support email address
104
93
 
105
- * `name` - **Required**
106
- * `address` - **Required**
107
- * `email` - **Required**
108
- * `line_items` - **Required**
94
+ * `phone` - Company phone number - _Optional_
109
95
 
110
- You can set as many line items on the receipts as you want. Just pass in an array with each item containing a name and a value to display on the receipt.
96
+ * `logo` - Logo to be displayed on the receipt - _Optional_
97
+ This can be either a Path, File, StringIO, or URL. Here are a few examples:
111
98
 
112
- * `logo` - *Optional*
99
+ ```ruby
100
+ logo: Rails.root.join("app/assets/images/logo.png")
101
+ logo: File.expand_path("./logo.png")
102
+ logo: File.open("app/assets/images/logo.png", "rb")
103
+ logo: "https://www.ruby-lang.org/images/header-ruby-logo@2x.png" # Downloaded with OpenURI
104
+ ```
113
105
 
114
- The logo must be either a string path to a file or a file-like object.
106
+ * `details` - Array of details about the Receipt, Invoice, Statement. Typically, this is receipt numbers, issue date, due date, status, etc.
115
107
 
116
- ```ruby
117
- logo: Rails.root.join("app/assets/images/logo.png")
118
- # or
119
- logo: File.open("app/assets/images/logo.png", "rb")
120
- ```
108
+ * `line_items` - Array of line items to be displayed in table format.
109
+
110
+ * `footer` - String for a message at the bottom of the PDF.
111
+
112
+ * `font` - Hash of paths to font files - _Optional_
121
113
 
122
- To use an image from a URL, we recommend using `open-uri` to open the remote file as a StringIO object.
114
+ ```ruby
115
+ font: {
116
+ bold: Rails.root.join('app/assets/fonts/tradegothic/TradeGothic-Bold.ttf'),
117
+ normal: Rails.root.join('app/assets/fonts/tradegothic/TradeGothic.ttf'),
118
+ }
119
+ ```
123
120
 
124
- `require 'open-uri'`
121
+ Here's an example of where each option is displayed.
125
122
 
126
- `logo: URI.open("https://www.ruby-lang.org/images/header-ruby-logo@2x.png")`
123
+ ![options](examples/images/options.jpg)
127
124
 
128
- * `font` - *Optional*
125
+ ### Formatting
129
126
 
130
- If you'd like to use your own custom font, you can pass in the file paths to the `normal` and `bold` variations of your font. The bold font variation is required because it is used in the default message. If you wish to override that, you can pass in your own custom message instead.
127
+ `details` and `line_items` allow inline formatting with Prawn. This allows you to use HTML tags to format text: `<b>` `<i>` `<u>` `<strikethrough>` `<sub>` `<sup>` `<font>` `<color>` `<link>`
131
128
 
132
- #### Internationalization (I18n)
129
+ See [the Prawn docs](https://prawnpdf.org/api-docs/2.3.0/Prawn/Text.html#text-instance_method) for more information.
130
+
131
+ ### Internationalization (I18n)
133
132
 
134
133
  You can use `I18n.t` when rendering your receipts to internationalize them.
135
134
 
@@ -141,21 +140,53 @@ line_items: [
141
140
  ]
142
141
  ```
143
142
 
144
- ## Rendering the Receipt PDF in your Controller
143
+ ### Custom PDF Content
145
144
 
146
- Here we have a charges controller that responds to the show action. When
147
- you visit it with the PDF format, it calls the `receipt` method that we
148
- just created on the `Charge` model.
145
+ You can change the entire PDF content by instantiating an Receipts object without any options.
149
146
 
150
- We set the filename to be the date plus the product name. You can
151
- customize the filename to your liking.
147
+ ```ruby
148
+ receipt = Receipts::Receipt.new # creates an empty PDF
149
+ ```
152
150
 
153
- Next we set the response type which will be `application/pdf`
151
+ Each Receipts object inherits from Prawn::Document. This allows you to choose what is rendered and include any custom Prawn content you like.
154
152
 
155
- Optionally we can set the `disposition` to `:inline` which allows us to
156
- render the PDF in the browser without forcing the download. If you
157
- delete this option or change it to `:attachment` then the receipt will
158
- be downloaded instead.
153
+ ```ruby
154
+ receipt.text("hello world")
155
+ ```
156
+
157
+ You can also use the Receipts helpers in your custom PDFs at the current cursor position.
158
+
159
+ ```ruby
160
+ receipt.text("Custom header")
161
+ receipt.render_line_items([
162
+ ["my line items"]
163
+ ])
164
+ receipt.render_footer("This is a custom footer using the Receipts helper")
165
+ ```
166
+
167
+ ### Rendering PDFs
168
+
169
+ To render a PDF in memory, use `render`. This is recommended for serving PDFs in your Rails controllers.
170
+
171
+ ```ruby
172
+ receipt.render
173
+ ```
174
+
175
+ To render a PDF to disk, use `render_file`:
176
+
177
+ ```ruby
178
+ receipt.render_file "receipt.pdf"
179
+ ```
180
+
181
+ ## Rendering PDFs in Rails controller actions
182
+
183
+ Here's an example Rails controller action you can use for serving PDFs. We'll first look up the database record for the `Charge` we want to render a receipt for.
184
+
185
+ The `Charge` model has a `receipt` method that returns a `Receipts::Receipt` instance with all the receipt data filled out.
186
+
187
+ Then we can `render` to generate the PDF in memory. This produces a String with the raw PDF data in it.
188
+
189
+ Using `send_data` from Rails, we can send the PDF contents and provide the browser with a recommended filename, content type and disposition.
159
190
 
160
191
  ```ruby
161
192
  class ChargesController < ApplicationController
@@ -164,12 +195,7 @@ class ChargesController < ApplicationController
164
195
 
165
196
  def show
166
197
  respond_to do |format|
167
- format.pdf {
168
- send_data @charge.receipt.render,
169
- filename: "#{@charge.created_at.strftime("%Y-%m-%d")}-gorails-receipt.pdf",
170
- type: "application/pdf",
171
- disposition: :inline
172
- }
198
+ format.pdf { send_pdf }
173
199
  end
174
200
  end
175
201
 
@@ -178,13 +204,18 @@ class ChargesController < ApplicationController
178
204
  def set_charge
179
205
  @charge = current_user.charges.find(params[:id])
180
206
  end
207
+
208
+ def send_pdf
209
+ # Render the PDF in memory and send as the response
210
+ send_data @charge.receipt.render,
211
+ filename: "#{@charge.created_at.strftime("%Y-%m-%d")}-gorails-receipt.pdf",
212
+ type: "application/pdf",
213
+ disposition: :inline # or :attachment to download
214
+ end
181
215
  end
182
216
  ```
183
217
 
184
- And that's it! Just create a `link_to` to your charge with the format of
185
- `pdf` and you're good to go.
186
-
187
- For example:
218
+ Then, just `link_to` to your charge with the format of `pdf`. For example:
188
219
 
189
220
  ```ruby
190
221
  # config/routes.rb
@@ -192,93 +223,78 @@ resources :charges
192
223
  ```
193
224
 
194
225
  ```erb
195
- <%= link_to "Download Receipt", charge_path(@charge, format: :pdf) %>
226
+ <%= link_to "View Receipt", charge_path(@charge, format: :pdf) %>
196
227
  ```
197
228
 
198
229
  ## Invoices
199
230
 
200
- Invoices follow the exact same set of steps as above, with a few minor changes and have a few extra arguments you can use:
201
-
202
- * `issue_date` - Date the invoice was issued
203
-
204
- * `due_date` - Date the invoice payment is due
205
-
206
- * `status` - A status for the invoice (Pending, Paid, etc)
207
-
208
- * `bill_to` - A string or Array of lines with billing details
209
-
210
- You can also use line_items to flexibly generate and display the table with items in it, including subtotal, taxes, and total amount.
231
+ Invoices follow the exact same set of steps as above. You'll simply want to modify the `details` to include other information for the Invoice such as the Issue Date, Due Date, etc.
211
232
 
212
233
  ```ruby
213
- Receipts::Invoice.new(
214
- id: "123",
215
- issue_date: Date.today,
216
- due_date: Date.today + 30,
217
- status: "<b><color rgb='#5eba7d'>PAID</color></b>",
218
- bill_to: [
219
- "GoRails, LLC",
220
- "123 Fake Street",
221
- "New York City, NY 10012",
222
- nil,
223
- "mail@example.com",
224
- ],
225
- company: {
226
- name: "GoRails, LLC",
227
- address: "123 Fake Street\nNew York City, NY 10012",
228
- email: "support@example.com",
229
- logo: File.expand_path("./examples/gorails.png")
230
- },
231
- line_items: [
232
- ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
233
- ["GoRails Subscription", "$19.00", "1", "$19.00"],
234
- [nil, nil, "Subtotal", "$19.00"],
235
- [nil, nil, "Tax Rate", "0%"],
236
- [nil, nil, "Total", "$19.00"],
237
- ],
238
- )
234
+ Receipts::Invoice.new(
235
+ details: [
236
+ ["Invoice Number", "123"],
237
+ ["Issue Date", Date.today.strftime("%B %d, %Y")],
238
+ ["Due Date", Date.today.strftime("%B %d, %Y")],
239
+ ["Status", "<b><color rgb='#5eba7d'>PAID</color></b>"]
240
+ ],
241
+ recipient: [
242
+ "<b>Bill To</b>",
243
+ "Customer",
244
+ "Address",
245
+ "City, State Zipcode",
246
+ "customer@example.org"
247
+ ],
248
+ company: {
249
+ name: "Example, LLC",
250
+ address: "123 Fake Street\nNew York City, NY 10012",
251
+ phone: "(555) 867-5309",
252
+ email: "support@example.com",
253
+ logo: File.expand_path("./examples/images/logo.png")
254
+ },
255
+ line_items: [
256
+ ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
257
+ ["Subscription", "$19.00", "1", "$19.00"],
258
+ [nil, nil, "Subtotal", "$19.00"],
259
+ [nil, nil, "Tax Rate", "0%"],
260
+ [nil, nil, "Amount Due", "$19.00"]
261
+ ]
262
+ )
239
263
  ```
240
264
 
241
265
  ## Statements
242
266
 
243
- Statements follow the exact same set of steps as receipts, with a few minor changes and have a few extra arguments you can use:
244
-
245
- * `issue_date` - Date the invoice was issued
246
-
247
- * `start_date` - The start date of the statement period
248
-
249
- * `start_date` - The end date of the statement period
250
-
251
- * `bill_to` - A string or Array of lines with account details
252
-
253
- You can also use line_items to flexibly generate and display the table with items in it, including subtotal, taxes, and total amount.
267
+ Statements follow the exact same set of steps as above. You'll simply want to modify the `details` to include other information for the Invoice such as the Issue Date, Start and End Dates, etc.
254
268
 
255
269
  ```ruby
256
- Receipts::Statement.new(
257
- id: "123",
258
- issue_date: Date.today,
259
- start_date: Date.today - 30,
260
- end_date: Date.today,
261
- bill_to: [
262
- "GoRails, LLC",
263
- "123 Fake Street",
264
- "New York City, NY 10012",
265
- nil,
266
- "mail@example.com",
267
- ],
268
- company: {
269
- name: "GoRails, LLC",
270
- address: "123 Fake Street\nNew York City, NY 10012",
271
- email: "support@example.com",
272
- logo: File.expand_path("./examples/gorails.png")
273
- },
274
- line_items: [
275
- ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
276
- ["GoRails Subscription", "$19.00", "1", "$19.00"],
277
- [nil, nil, "Subtotal", "$19.00"],
278
- [nil, nil, "Tax Rate", "0%"],
279
- [nil, nil, "Total", "$19.00"],
280
- ],
281
- )
270
+ Receipts::Statement.new(
271
+ details: [
272
+ ["Statement Number", "123"],
273
+ ["Issue Date", Date.today.strftime("%B %d, %Y")],
274
+ ["Period", "#{(Date.today - 30).strftime("%B %d, %Y")} - #{Date.today.strftime("%B %d, %Y")}"]
275
+ ],
276
+ recipient: [
277
+ "<b>Bill To</b>",
278
+ "Customer",
279
+ "Address",
280
+ "City, State Zipcode",
281
+ "customer@example.org"
282
+ ],
283
+ company: {
284
+ name: "Example, LLC",
285
+ address: "123 Fake Street\nNew York City, NY 10012",
286
+ email: "support@example.com",
287
+ phone: "(555) 867-5309",
288
+ logo: File.expand_path("./examples/images/logo.png")
289
+ },
290
+ line_items: [
291
+ ["<b>Item</b>", "<b>Unit Cost</b>", "<b>Quantity</b>", "<b>Amount</b>"],
292
+ ["Subscription", "$19.00", "1", "$19.00"],
293
+ [nil, nil, "Subtotal", "$19.00"],
294
+ [nil, nil, "Tax Rate", "0%"],
295
+ [nil, nil, "Total", "$19.00"]
296
+ ]
297
+ )
282
298
  ```
283
299
 
284
300
  ## Contributing