stripe_invoice 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/Rakefile +6 -13
- data/app/controllers/stripe_invoice/invoices_controller.rb +51 -20
- data/app/helpers/stripe_invoice/invoices_helper.rb +11 -0
- data/app/models/stripe_invoice/invoice.rb +11 -3
- data/app/views/stripe_invoice/invoices/index.html.haml +1 -1
- data/app/views/stripe_invoice/invoices/show.html.haml +11 -9
- data/app/views/stripe_invoice/invoices/show.pdf.prawn +58 -0
- data/db/migrate/20140605194026_create_stripe_invoice_invoices.rb +1 -1
- data/db/migrate/20141117125158_add_fields_into_stripe_invoice_invoices.rb +11 -0
- data/db/migrate/20141202074511_add_parent_invoice_id_into_stripe_invoice_invoices.rb +9 -0
- data/lib/stripe_invoice/engine.rb +12 -0
- data/lib/stripe_invoice/version.rb +1 -1
- data/spec/controllers/stripe_invoice/invoices_controller_spec.rb +58 -0
- data/{test → spec}/dummy/README.rdoc +0 -0
- data/{test → spec}/dummy/Rakefile +0 -0
- data/{test → spec}/dummy/app/assets/javascripts/application.js +0 -0
- data/{test → spec}/dummy/app/assets/stylesheets/application.css +0 -0
- data/{test → spec}/dummy/app/controllers/application_controller.rb +0 -0
- data/{test → spec}/dummy/app/helpers/application_helper.rb +0 -0
- data/{test → spec}/dummy/app/views/layouts/application.html.erb +0 -0
- data/{test → spec}/dummy/config/application.rb +0 -0
- data/{test → spec}/dummy/config/boot.rb +0 -0
- data/{test → spec}/dummy/config/database.yml +0 -0
- data/{test → spec}/dummy/config/environment.rb +0 -0
- data/{test → spec}/dummy/config/environments/development.rb +0 -0
- data/{test → spec}/dummy/config/environments/production.rb +0 -0
- data/{test → spec}/dummy/config/environments/test.rb +1 -0
- data/{test → spec}/dummy/config/initializers/backtrace_silencers.rb +0 -0
- data/{test → spec}/dummy/config/initializers/inflections.rb +0 -0
- data/{test → spec}/dummy/config/initializers/mime_types.rb +0 -0
- data/{test → spec}/dummy/config/initializers/secret_token.rb +1 -1
- data/{test → spec}/dummy/config/initializers/session_store.rb +0 -0
- data/{test → spec}/dummy/config/initializers/wrap_parameters.rb +0 -0
- data/{test → spec}/dummy/config/locales/en.yml +0 -0
- data/{test → spec}/dummy/config/routes.rb +0 -0
- data/{test → spec}/dummy/config.ru +0 -0
- data/{test/dummy/public/favicon.ico → spec/dummy/db/test.sqlite3} +0 -0
- data/{test → spec}/dummy/public/404.html +0 -0
- data/{test → spec}/dummy/public/422.html +0 -0
- data/{test → spec}/dummy/public/500.html +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/{test → spec}/dummy/script/rails +0 -0
- data/spec/factories/stripe_invoice_invoices_factory.rb +40 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/vcr_setup.rb +10 -0
- metadata +145 -76
- data/test/fixtures/stripe_invoice/invoices.yml +0 -11
- data/test/functional/stripe_invoice/invoices_controller_test.rb +0 -9
- data/test/integration/navigation_test.rb +0 -10
- data/test/stripe_invoice_test.rb +0 -7
- data/test/test_helper.rb +0 -15
- data/test/unit/helpers/stripe_invoice/invoices_helper_test.rb +0 -6
- data/test/unit/stripe_invoice/invoice_test.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20da253e1cd8256f9a83fdff32032f4e296e519c
|
4
|
+
data.tar.gz: 31614a75ebf67a5426967dcb7f092d650172529b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c275a01506f4d2586a1b8c1f198c017d4fea5c8a788027a4876be3ac9e850294dc5906a2253437c5f6f2d90201f243ccd27dacd80b578278f141a9963a7f8b8
|
7
|
+
data.tar.gz: 50bbbd8caed4779b00fe77994d2f12274199d5645c7d60a56b834bd9221f1ea5f511b805078aa8857256f7390837075226f77ec00d4baff577b2fa178bcae918
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ gem 'stripe_invoice'
|
|
31
31
|
To setup your application run the following commands from the command line:
|
32
32
|
|
33
33
|
```
|
34
|
-
rails
|
34
|
+
rails generate stripe_invoice:install
|
35
35
|
rake db:migrate
|
36
36
|
```
|
37
37
|
|
@@ -60,4 +60,4 @@ To contribute to the development of StripeInvoice please:
|
|
60
60
|
4. send a pull request
|
61
61
|
|
62
62
|
## Developer
|
63
|
-
This plugin is under active development by [Christoph Engelhardt](http://www.it-engelhardt.de) and used at [LinksSpy.com](http://www.linksspy.com)
|
63
|
+
This plugin is under active development by [Christoph Engelhardt](http://www.it-engelhardt.de) and used at [LinksSpy.com](http://www.linksspy.com)
|
data/Rakefile
CHANGED
@@ -20,21 +20,14 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
20
20
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
21
|
end
|
22
22
|
|
23
|
-
APP_RAKEFILE = File.expand_path("../
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
24
|
load 'rails/tasks/engine.rake'
|
25
25
|
|
26
|
-
|
27
|
-
|
28
26
|
Bundler::GemHelper.install_tasks
|
29
27
|
|
30
|
-
require '
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
t.libs << 'test'
|
35
|
-
t.pattern = 'test/**/*_test.rb'
|
36
|
-
t.verbose = false
|
37
|
-
end
|
38
|
-
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
31
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
39
32
|
|
40
|
-
task :default => :
|
33
|
+
task :default => :spec
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require_dependency "stripe_invoice/application_controller"
|
2
|
-
require
|
2
|
+
require "prawn-rails"
|
3
3
|
|
4
4
|
module StripeInvoice
|
5
5
|
class InvoicesController < ApplicationController
|
@@ -7,29 +7,41 @@ module StripeInvoice
|
|
7
7
|
def index
|
8
8
|
@owner = send("current_#{::Koudoku.subscriptions_owned_by}")
|
9
9
|
redirect_to '/' unless @owner
|
10
|
-
|
10
|
+
|
11
11
|
@subscription = @owner.subscription
|
12
|
-
|
13
12
|
if @subscription
|
14
13
|
# I know this looks silly, but Koudoku actually stores the customer's stripe_id
|
15
14
|
# in the subscription model
|
16
|
-
@
|
15
|
+
@stripe_charges = Stripe::Charge.all(
|
17
16
|
:customer => @subscription.stripe_id,
|
18
17
|
:limit => 100)
|
19
|
-
|
20
|
-
@
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
|
19
|
+
@stripe_charges.each do |scharge|
|
20
|
+
scharge_invoice = Stripe::Invoice.retrieve(scharge.invoice) rescue {}
|
21
|
+
|
22
|
+
next if scharge_invoice.blank?
|
23
|
+
# We can use below to get parent_invoice id instead of fetching agin to get exect parent, because parent should come first always.
|
24
|
+
# available_invoices = Invoice.find_all_by_stripe_id(scharge_invoice.id)
|
25
|
+
# available_invoices.first.id
|
26
|
+
invoice_count = Invoice.find_all_by_stripe_id(scharge_invoice.id).count
|
27
|
+
scharge_count = scharge.refunds.count + 1
|
28
|
+
next if scharge_count == invoice_count #Execute next if count is equal. But here we can miss the case if refund get updated.
|
29
|
+
#Do we need to make one flag 'refund_deleted' to manage refund deleted or not ?
|
30
|
+
|
31
|
+
generate_invoice(scharge, @owner, scharge_invoice) if invoice_count==0
|
32
|
+
|
33
|
+
#Check for refund and create invoice
|
34
|
+
if scharge.refunds.present?
|
35
|
+
parent_invoice = Invoice.where({stripe_id: scharge_invoice.id, parent_invoice_id: nil}).first
|
36
|
+
scharge.refunds.each do |scharge_refund|
|
37
|
+
next if Invoice.find_by_stripe_refund_id(scharge_refund.id).present?
|
38
|
+
generate_invoice(scharge, @owner, scharge_invoice, scharge_refund, parent_invoice)
|
39
|
+
end
|
40
|
+
end # if scharge.refunds
|
29
41
|
end
|
30
42
|
end # if subscription
|
31
43
|
|
32
|
-
@invoices = Invoice.where(owner_id: @owner.id).order('date DESC')
|
44
|
+
@invoices = Invoice.where({owner_id: @owner.id, parent_invoice_id: nil}).order('stripe_id, date DESC')
|
33
45
|
end
|
34
46
|
|
35
47
|
def show
|
@@ -40,12 +52,31 @@ module StripeInvoice
|
|
40
52
|
|
41
53
|
respond_to do |format|
|
42
54
|
format.html {render layout: false}
|
43
|
-
format.pdf
|
44
|
-
html = render_to_string(layout: false, formats: [:html])
|
45
|
-
pdf = ::PDFKit.new(html, page_size: 'Letter')
|
46
|
-
send_data(pdf.to_pdf, filename: "invoice-#{@invoice.number}.pdf")
|
47
|
-
end
|
55
|
+
format.pdf
|
48
56
|
end
|
49
57
|
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def generate_invoice(scharge, owner, scharge_invoice, scharge_refund=nil, parent_invoice=nil)
|
62
|
+
amount, stripe_refund_id, parent_invoice_id = scharge_invoice[:total], nil, nil
|
63
|
+
if scharge_refund.present?
|
64
|
+
amount = -scharge_refund.amount #'-' For refund
|
65
|
+
stripe_refund_id = scharge_refund.id
|
66
|
+
parent_invoice_id = parent_invoice.id if parent_invoice.present?
|
67
|
+
end
|
68
|
+
|
69
|
+
Invoice.create({
|
70
|
+
stripe_id: scharge_invoice.id,
|
71
|
+
owner_id: owner.id,
|
72
|
+
date: scharge.created,
|
73
|
+
invoice_number: "ls-#{Date.today.year}-#{(Invoice.last ? (Invoice.last.id * 7) : 1).to_s.rjust(5, '0')}",
|
74
|
+
json: scharge_invoice,
|
75
|
+
amount: amount,
|
76
|
+
stripe_refund_id: stripe_refund_id,
|
77
|
+
parent_invoice_id: parent_invoice_id
|
78
|
+
})
|
79
|
+
end
|
80
|
+
|
50
81
|
end
|
51
82
|
end
|
@@ -38,5 +38,16 @@ module StripeInvoice
|
|
38
38
|
plan [:metadata][:stripe_invoice] &&
|
39
39
|
plan[:metadata][:stripe_invoice][:public_name]) || plan[:name]
|
40
40
|
end
|
41
|
+
|
42
|
+
def pdf_date_format(date)
|
43
|
+
date = Time.at(date)
|
44
|
+
date.strftime('%d/%m/%Y')
|
45
|
+
end
|
46
|
+
|
47
|
+
def plan_duration_in_month(invoice)
|
48
|
+
period_end_date = Time.at(invoice.period_end)
|
49
|
+
period_start_date = Time.at(invoice.period_start)
|
50
|
+
((period_end_date.year * 12 + period_end_date.month) - (period_start_date.year * 12 + period_start_date.month)).to_i
|
51
|
+
end
|
41
52
|
end
|
42
53
|
end
|
@@ -1,17 +1,15 @@
|
|
1
1
|
module StripeInvoice
|
2
2
|
class Invoice < ActiveRecord::Base
|
3
|
-
attr_accessible :id, :invoice_number, :stripe_id, :json, :owner_id, :date
|
3
|
+
attr_accessible :id, :invoice_number, :stripe_id, :json, :owner_id, :date, :amount, :stripe_refund_id, :parent_invoice_id
|
4
4
|
|
5
5
|
alias_attribute :number, :invoice_number
|
6
6
|
|
7
7
|
serialize :json, JSON
|
8
8
|
|
9
|
-
|
10
9
|
def indifferent_json
|
11
10
|
@json ||= json.with_indifferent_access
|
12
11
|
end
|
13
12
|
|
14
|
-
|
15
13
|
def subtotal
|
16
14
|
indifferent_json[:subtotal]
|
17
15
|
end
|
@@ -39,5 +37,15 @@ module StripeInvoice
|
|
39
37
|
def lines
|
40
38
|
indifferent_json[:lines]
|
41
39
|
end
|
40
|
+
|
41
|
+
def refunds
|
42
|
+
Invoice.where(parent_invoice_id: id)
|
43
|
+
end
|
44
|
+
|
45
|
+
def total_refund
|
46
|
+
total_refund=0
|
47
|
+
refunds.each{ |refund| total_refund += -refund.amount}
|
48
|
+
total_refund
|
49
|
+
end
|
42
50
|
end
|
43
51
|
end
|
@@ -9,4 +9,4 @@
|
|
9
9
|
%tr
|
10
10
|
%td= link_to invoice.id, invoice_path(invoice.id)
|
11
11
|
%td= "#{l(Time.at(invoice.period_start).to_datetime, :format => :short_date)} - #{l(Time.at(invoice.period_end).to_datetime, :format => :short_date)}"
|
12
|
-
%td= format_currency invoice.
|
12
|
+
%td= format_currency((invoice.amount - invoice.total_refund), invoice.currency)
|
@@ -1,25 +1,27 @@
|
|
1
1
|
%table(border=1)
|
2
2
|
%tr
|
3
|
-
%td
|
3
|
+
%td Name
|
4
4
|
%td value
|
5
5
|
%tr
|
6
|
-
%td
|
6
|
+
%td Id
|
7
7
|
%td= @invoice.id
|
8
8
|
%tr
|
9
|
-
%td
|
9
|
+
%td Period Start
|
10
10
|
%td= @invoice.period_start
|
11
11
|
%tr
|
12
|
-
%td
|
12
|
+
%td Period End
|
13
13
|
%td= @invoice.period_end
|
14
14
|
%tr
|
15
|
-
%td
|
15
|
+
%td Subtotal
|
16
16
|
%td= format_currency(@invoice.subtotal, @invoice.currency)
|
17
17
|
- if @invoice.discount
|
18
18
|
%tr
|
19
19
|
%td discount
|
20
20
|
%td= format_currency(@invoice.discount, @invoice.currency)
|
21
|
+
- @invoice.refunds.each do |refund|
|
22
|
+
%tr
|
23
|
+
%td= 'Refund'
|
24
|
+
%td= format_currency(refund.amount, @invoice.currency)
|
21
25
|
%tr
|
22
|
-
%td
|
23
|
-
%td= format_currency(@invoice.
|
24
|
-
|
25
|
-
|
26
|
+
%td Total
|
27
|
+
%td= format_currency((@invoice.amount - @invoice.total_refund), @invoice.currency)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
pdf.font("Times-Roman") #Prawn does not support Arial.
|
2
|
+
pdf.fill_color "333333"
|
3
|
+
pdf.font_size = 16
|
4
|
+
|
5
|
+
#Invoice Details Container
|
6
|
+
pdf.font_size(17.5) { pdf.text "Invoice Details", :style => :bold }
|
7
|
+
|
8
|
+
pdf.move_down 10
|
9
|
+
|
10
|
+
invoiceinfo = [['Date', "#{pdf_date_format(@invoice.date)}"],
|
11
|
+
["Invoice #", "#{@invoice.invoice_number}"],
|
12
|
+
["Billed To", "[BILLED TO]"],
|
13
|
+
["VAT ID ", "[VAT-ID]"]]
|
14
|
+
|
15
|
+
pdf.table(invoiceinfo,:cell_style => { :border_width => 0,:border_color=> 'C1C1C1', :width=>'100%' }) do |table|
|
16
|
+
table.column(0..1).style(:align => :left)
|
17
|
+
table.column(0).width = 150
|
18
|
+
table.column(1).width = 390
|
19
|
+
table.row(0..3).style(:border_width => 1, :borders => [:top], :color => 'dddddd')
|
20
|
+
end
|
21
|
+
pdf.move_down 20
|
22
|
+
|
23
|
+
#Summary Container
|
24
|
+
pdf.font_size(17.5) { pdf.text "Summary", :style => :bold }
|
25
|
+
pdf.move_down 10
|
26
|
+
|
27
|
+
rows = [['Subtotal', "#{format_currency(@invoice.subtotal, @invoice.currency)}"]]
|
28
|
+
|
29
|
+
#Refund details
|
30
|
+
@invoice.refunds.each do |refund|
|
31
|
+
rows << ["Refund", "#{format_currency(refund.amount, @invoice.currency)}"]
|
32
|
+
end
|
33
|
+
|
34
|
+
rows << ["Total", "#{format_currency((@invoice.amount - @invoice.total_refund), @invoice.currency)}"]
|
35
|
+
pdf.table(rows,:cell_style => { :border_width => 0,:border_color=> 'C1C1C1', :width=>'100%' }) do |table|
|
36
|
+
table.column(0..1).style(:align => :right)
|
37
|
+
table.column(0).width = 300
|
38
|
+
table.column(1).width = 240
|
39
|
+
table.row(0..3).style(:border_width => 1, :borders => [:top], :color => 'dddddd')
|
40
|
+
end
|
41
|
+
pdf.move_down 30
|
42
|
+
|
43
|
+
#Line Items Container
|
44
|
+
pdf.font_size(17.5) { pdf.text "Line Items", :style => :bold }
|
45
|
+
pdf.move_down 10
|
46
|
+
|
47
|
+
line_items = [["#{pluralize(plan_duration_in_month(@invoice), 'month')} LinksSpy.com subscription [plan: #{@invoice["json"]["lines"]["data"][0]["plan"]["name"]}]", "#{pdf_date_format(@invoice.period_start)} - #{pdf_date_format(@invoice.period_end)}", "#{format_currency(( @invoice.amount - @invoice.total_refund), @invoice.currency)}"]]
|
48
|
+
pdf.font_size = 14
|
49
|
+
|
50
|
+
pdf.table(line_items,:cell_style => { :border_width => 0,:border_color=> 'C1C1C1', :width=>'100%' }) do |table|
|
51
|
+
table.column(0).style(:align => :left)
|
52
|
+
table.column(1).style(:align => :center)
|
53
|
+
table.column(2).style(:align => :right)
|
54
|
+
table.column(0).width = 330
|
55
|
+
table.column(1).width = 150
|
56
|
+
table.column(2).width = 60
|
57
|
+
table.row(0).style(:border_width => 1, :borders => [:top], :color => 'dddddd')
|
58
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddFieldsIntoStripeInvoiceInvoices < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
add_column :stripe_invoice_invoices, :amount, :integer, :default => 0
|
4
|
+
add_column :stripe_invoice_invoices, :stripe_refund_id, :string
|
5
|
+
end
|
6
|
+
|
7
|
+
def down
|
8
|
+
remove_column :stripe_invoice_invoices, :amount
|
9
|
+
remove_column :stripe_invoice_invoices, :stripe_refund_id
|
10
|
+
end
|
11
|
+
end
|
@@ -1,7 +1,19 @@
|
|
1
1
|
module StripeInvoice
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace StripeInvoice
|
4
|
+
config.generators do |g|
|
5
|
+
g.test_framework :rspec, :fixture => false
|
6
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
7
|
+
g.assets false
|
8
|
+
g.helper false
|
9
|
+
end
|
4
10
|
|
11
|
+
initializer :append_migrations do |app|
|
12
|
+
unless app.root.to_s.match root.to_s
|
13
|
+
app.config.paths["db/migrate"] += config.paths["db/migrate"].expanded
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
5
17
|
# loads StripeInvoice::ApplicationHelper into ::ApplicationController
|
6
18
|
# so we can use #stripe_invoice_controller? in the main_app
|
7
19
|
initializer 'load_stripe_invoice_helpers' do
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "StripeInvoice::InvoicesController" do
|
4
|
+
let(:invoice) {FactoryGirl.create(:invoice)}
|
5
|
+
|
6
|
+
# let(:subscription) {{id: 2, stripe_id: "cus_55dfC5lHHzhyl3", plan_id: 1, last_four: "1111", coupon_id: nil, card_type: "undefined", current_price: 10.0, user_id: 2, created_at: "2014-11-05 11:55:28", updated_at: "2014-11-05 11:55:28"}}
|
7
|
+
# context 'Index action', :vcr do
|
8
|
+
# before do
|
9
|
+
# ::Koudoku.stub(:subscriptions_owned_by).and_return(:user)
|
10
|
+
# ApplicationController.any_instance.stub(:current_user).and_return({id: 1, email: "ankur@mail.com", encrypted_password: "$2a$10$13AxhtcJM76hKRjTh/0VfOT0cQ0ScqL.Q.vM6AXRE9O5...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-11-03 11:50:22", last_sign_in_at: "2014-11-03 11:50:22", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-11-03 11:50:22", updated_at: "2014-11-03 11:50:23", subscription: subscription}.with_indifferent_access.to_obj)
|
11
|
+
# end
|
12
|
+
|
13
|
+
# it "should generate all the invoice from charges & refunds" do
|
14
|
+
# VCR.use_cassette 'get_all_charges' do
|
15
|
+
# visit "/stripe_invoice/invoices"
|
16
|
+
# expect(response).to render_template(:index)
|
17
|
+
# expect(StripeInvoice::Invoice.count).to eq(11)
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
context 'Show action' do
|
23
|
+
before do
|
24
|
+
::Koudoku.stub(:subscriptions_owned_by).and_return(:user)
|
25
|
+
ApplicationController.any_instance.stub(:current_user).and_return({id: 1, email: "ankur@mail.com", encrypted_password: "$2a$10$13AxhtcJM76hKRjTh/0VfOT0cQ0ScqL.Q.vM6AXRE9O5...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-11-03 11:50:22", last_sign_in_at: "2014-11-03 11:50:22", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-11-03 11:50:22", updated_at: "2014-11-03 11:50:23"})
|
26
|
+
visit "/stripe_invoice/invoices/#{invoice.id}.pdf"
|
27
|
+
@ext_analysis = PDF::Inspector::Text.analyze(page.body)
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'Invoice PDF' do
|
31
|
+
|
32
|
+
it "Should download the pdf when visiting the show page" do
|
33
|
+
expect(response).to render_template(:show)
|
34
|
+
expect(page.response_headers['Content-Type']).to eq("application/pdf; charset=utf-8")
|
35
|
+
end
|
36
|
+
|
37
|
+
['Invoice #', 'Invoice Details', 'Billed To', 'VAT ID',
|
38
|
+
'Summary', 'Subtotal', 'Total', 'Line Items'].each do |pdf_text|
|
39
|
+
it "The pdf should have the correct label : #{pdf_text}" do
|
40
|
+
expect(@ext_analysis.strings).to include(pdf_text)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# To check the value on the pdf
|
45
|
+
it "The pdf should have the correct values" do
|
46
|
+
["#{Time.at(invoice.date).strftime('%d/%m/%Y')}",
|
47
|
+
invoice.invoice_number,
|
48
|
+
"[BILLED TO]",
|
49
|
+
"[VAT-ID]",
|
50
|
+
"#{Time.at(invoice.period_start).strftime('%d/%m/%Y')} - #{Time.at(invoice.period_end).strftime('%d/%m/%Y')}"
|
51
|
+
].each do |pdf_value|
|
52
|
+
expect(@ext_analysis.strings).to include(pdf_value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -4,4 +4,4 @@
|
|
4
4
|
# If you change this key, all old signed cookies will become invalid!
|
5
5
|
# Make sure the secret is at least 30 characters and all random,
|
6
6
|
# no regular words or you'll be exposed to dictionary attacks.
|
7
|
-
Dummy::Application.config.secret_token = '
|
7
|
+
Dummy::Application.config.secret_token = '00cdbb2fc9a8f887b69f2f8a8b5ba311ae3be2efe5417b2b563bb01cff32213aa1de46841977b638e14cd4ca2de7740827f3e105c057e57939142ff1e96e2f75'
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,40 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
sequence :invoice_number do |n|
|
3
|
+
"ls-2014-0#{n}"
|
4
|
+
end
|
5
|
+
|
6
|
+
factory :invoice, :class => StripeInvoice::Invoice do
|
7
|
+
created_at Time.now
|
8
|
+
date DateTime.now
|
9
|
+
invoice_number
|
10
|
+
json {{
|
11
|
+
"id" => "in_14ulSoD8GNoNEK6vB5oT8muW","date" => Time.now.to_i,"period_start" => Time.now.to_i,
|
12
|
+
"period_end" => 10.days.from_now.to_i,
|
13
|
+
"lines" => {"object" => "list","total_count" => 1,"has_more" => false,
|
14
|
+
"url" => "/v1/invoices/in_14ulSoD8GNoNEK6vB5oT8muW/lines",
|
15
|
+
"data" => [{"id" => "sub_54vJz44uQsUcT8","object" => "line_item",
|
16
|
+
"type" => "subscription","livemode" => false,"amount" => 0,
|
17
|
+
"currency" => "usd","proration" => false,
|
18
|
+
"period" => {"start" => Time.now.to_i,"end" => 10.days.from_now.to_i},
|
19
|
+
"subscription" => nil,"quantity" => 1,
|
20
|
+
"plan" => {"id" => "3","interval" => "month","name" => "Enterprise",
|
21
|
+
"created" => Time.now.to_i,"amount" => 111,"currency" => "usd",
|
22
|
+
"object" => "plan","livemode" => false,"interval_count" => 1,
|
23
|
+
"trial_period_days" => 10,"metadata" => {},
|
24
|
+
"statement_description" => "test"},
|
25
|
+
"description" => nil,"metadata" => {}}]
|
26
|
+
},
|
27
|
+
"subtotal" => 0,"total" => 0,"customer" => "cus_54vJXgyRP01m9B",
|
28
|
+
"object" => "invoice","attempted" => true,"closed" => true,
|
29
|
+
"forgiven" => false,"paid" => true,"livemode" => false,
|
30
|
+
"attempt_count" => 0,"amount_due" => 0,"currency" => "usd",
|
31
|
+
"starting_balance" => 0,"ending_balance" => 0,"next_payment_attempt" => nil,
|
32
|
+
"webhooks_delivered_at" => Time.now.to_i,"charge" => nil,"discount" => nil,
|
33
|
+
"application_fee" => nil,"subscription" => "sub_54vJz44uQsUcT8","metadata" => {},
|
34
|
+
"statement_description" => nil,"description" => nil,"receipt_number" => nil
|
35
|
+
}} #TODO:: Does this need to be randomized?
|
36
|
+
owner_id 1 # Hardcoded as we do not have the user model here.
|
37
|
+
stripe_id "in_14ulSoD8GNoNEK6vB5oT8muW"
|
38
|
+
updated_at Time.now
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
3
|
+
require File.expand_path("../dummy/config/environment", __FILE__)
|
4
|
+
require 'rspec/rails'
|
5
|
+
require 'rspec/autorun'
|
6
|
+
require 'factory_girl_rails'
|
7
|
+
require 'koudoku'
|
8
|
+
require 'pry'
|
9
|
+
require 'pdf/inspector'
|
10
|
+
require 'vcr'
|
11
|
+
|
12
|
+
Rails.backtrace_cleaner.remove_silencers!
|
13
|
+
|
14
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
15
|
+
# in spec/support/ and its subdirectories.
|
16
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.mock_with :rspec
|
20
|
+
config.use_transactional_fixtures = true
|
21
|
+
config.infer_base_class_for_anonymous_controllers = false
|
22
|
+
config.order = "random"
|
23
|
+
|
24
|
+
FactoryGirl.definition_file_paths = [File.expand_path('../factories', __FILE__)]
|
25
|
+
FactoryGirl.find_definitions
|
26
|
+
|
27
|
+
#Stipe configuration
|
28
|
+
Stripe.api_key = ENV['STRIPE_SECRET_KEY']
|
29
|
+
end
|
30
|
+
|
31
|
+
# class ::Hash
|
32
|
+
# # add keys to hash
|
33
|
+
# def to_obj
|
34
|
+
# self.each do |k,v|
|
35
|
+
# if v.kind_of? Hash
|
36
|
+
# v.to_obj
|
37
|
+
# end
|
38
|
+
# k=k.gsub(/\.|\s|-|\/|\'/, '_').downcase.to_sym
|
39
|
+
|
40
|
+
# ## create and initialize an instance variable for this key/value pair
|
41
|
+
# self.instance_variable_set("@#{k}", v)
|
42
|
+
|
43
|
+
# ## create the getter that returns the instance variable
|
44
|
+
# self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
|
45
|
+
|
46
|
+
# ## create the setter that sets the instance variable
|
47
|
+
# self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
|
48
|
+
# end
|
49
|
+
# return self
|
50
|
+
# end
|
51
|
+
# end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# spec/support/vcr_setup.rb
|
2
|
+
VCR.configure do |c|
|
3
|
+
#the directory where your cassettes will be saved
|
4
|
+
c.cassette_library_dir = 'spec/vcr'
|
5
|
+
# your HTTP request service. You can also use fakeweb, webmock, and more
|
6
|
+
c.hook_into :webmock
|
7
|
+
c.default_cassette_options = { record: :new_episodes }
|
8
|
+
c.configure_rspec_metadata!
|
9
|
+
allow_http_connections_when_no_cassette = true
|
10
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stripe_invoice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christoph Engelhardt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: prawn-rails
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: haml-rails
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,13 +67,83 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rspec-rails
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
|
-
type: :
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: koudoku
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: devise
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: capybara
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: factory_girl_rails
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
77
147
|
prerelease: false
|
78
148
|
version_requirements: !ruby/object:Gem::Requirement
|
79
149
|
requirements:
|
@@ -117,49 +187,50 @@ files:
|
|
117
187
|
- app/views/layouts/stripe_invoice/application.html.erb
|
118
188
|
- app/views/stripe_invoice/invoices/index.html.haml
|
119
189
|
- app/views/stripe_invoice/invoices/show.html.haml
|
190
|
+
- app/views/stripe_invoice/invoices/show.pdf.prawn
|
120
191
|
- config/routes.rb
|
121
192
|
- db/migrate/20140605194026_create_stripe_invoice_invoices.rb
|
193
|
+
- db/migrate/20141117125158_add_fields_into_stripe_invoice_invoices.rb
|
194
|
+
- db/migrate/20141202074511_add_parent_invoice_id_into_stripe_invoice_invoices.rb
|
122
195
|
- lib/generators/stripe_invoice/install_generator.rb
|
123
196
|
- lib/generators/stripe_invoice/views_generator.rb
|
124
197
|
- lib/stripe_invoice.rb
|
125
198
|
- lib/stripe_invoice/engine.rb
|
126
199
|
- lib/stripe_invoice/version.rb
|
127
200
|
- lib/tasks/stripe_invoice_tasks.rake
|
128
|
-
-
|
129
|
-
-
|
130
|
-
-
|
131
|
-
-
|
132
|
-
-
|
133
|
-
-
|
134
|
-
-
|
135
|
-
-
|
136
|
-
-
|
137
|
-
-
|
138
|
-
-
|
139
|
-
-
|
140
|
-
-
|
141
|
-
-
|
142
|
-
-
|
143
|
-
-
|
144
|
-
-
|
145
|
-
-
|
146
|
-
-
|
147
|
-
-
|
148
|
-
-
|
149
|
-
-
|
150
|
-
-
|
151
|
-
-
|
152
|
-
-
|
153
|
-
-
|
154
|
-
-
|
155
|
-
-
|
156
|
-
-
|
157
|
-
-
|
158
|
-
-
|
159
|
-
-
|
160
|
-
-
|
161
|
-
- test/unit/helpers/stripe_invoice/invoices_helper_test.rb
|
162
|
-
- test/unit/stripe_invoice/invoice_test.rb
|
201
|
+
- spec/controllers/stripe_invoice/invoices_controller_spec.rb
|
202
|
+
- spec/dummy/README.rdoc
|
203
|
+
- spec/dummy/Rakefile
|
204
|
+
- spec/dummy/app/assets/javascripts/application.js
|
205
|
+
- spec/dummy/app/assets/stylesheets/application.css
|
206
|
+
- spec/dummy/app/controllers/application_controller.rb
|
207
|
+
- spec/dummy/app/helpers/application_helper.rb
|
208
|
+
- spec/dummy/app/views/layouts/application.html.erb
|
209
|
+
- spec/dummy/config.ru
|
210
|
+
- spec/dummy/config/application.rb
|
211
|
+
- spec/dummy/config/boot.rb
|
212
|
+
- spec/dummy/config/database.yml
|
213
|
+
- spec/dummy/config/environment.rb
|
214
|
+
- spec/dummy/config/environments/development.rb
|
215
|
+
- spec/dummy/config/environments/production.rb
|
216
|
+
- spec/dummy/config/environments/test.rb
|
217
|
+
- spec/dummy/config/initializers/backtrace_silencers.rb
|
218
|
+
- spec/dummy/config/initializers/inflections.rb
|
219
|
+
- spec/dummy/config/initializers/mime_types.rb
|
220
|
+
- spec/dummy/config/initializers/secret_token.rb
|
221
|
+
- spec/dummy/config/initializers/session_store.rb
|
222
|
+
- spec/dummy/config/initializers/wrap_parameters.rb
|
223
|
+
- spec/dummy/config/locales/en.yml
|
224
|
+
- spec/dummy/config/routes.rb
|
225
|
+
- spec/dummy/db/test.sqlite3
|
226
|
+
- spec/dummy/public/404.html
|
227
|
+
- spec/dummy/public/422.html
|
228
|
+
- spec/dummy/public/500.html
|
229
|
+
- spec/dummy/public/favicon.ico
|
230
|
+
- spec/dummy/script/rails
|
231
|
+
- spec/factories/stripe_invoice_invoices_factory.rb
|
232
|
+
- spec/spec_helper.rb
|
233
|
+
- spec/support/vcr_setup.rb
|
163
234
|
homepage: https://github.com/yas4891/stripe_invoice
|
164
235
|
licenses: []
|
165
236
|
metadata: {}
|
@@ -185,38 +256,36 @@ specification_version: 4
|
|
185
256
|
summary: Adds views, PDFs and automated emails if you are using Stripe/Koudoku for
|
186
257
|
payment processing
|
187
258
|
test_files:
|
188
|
-
-
|
189
|
-
-
|
190
|
-
-
|
191
|
-
-
|
192
|
-
-
|
193
|
-
-
|
194
|
-
-
|
195
|
-
-
|
196
|
-
-
|
197
|
-
-
|
198
|
-
-
|
199
|
-
-
|
200
|
-
-
|
201
|
-
-
|
202
|
-
-
|
203
|
-
-
|
204
|
-
-
|
205
|
-
-
|
206
|
-
-
|
207
|
-
-
|
208
|
-
-
|
209
|
-
-
|
210
|
-
-
|
211
|
-
-
|
212
|
-
-
|
213
|
-
-
|
214
|
-
-
|
215
|
-
-
|
216
|
-
-
|
217
|
-
-
|
218
|
-
-
|
219
|
-
-
|
220
|
-
-
|
221
|
-
- test/unit/helpers/stripe_invoice/invoices_helper_test.rb
|
222
|
-
- test/unit/stripe_invoice/invoice_test.rb
|
259
|
+
- spec/controllers/stripe_invoice/invoices_controller_spec.rb
|
260
|
+
- spec/dummy/app/assets/javascripts/application.js
|
261
|
+
- spec/dummy/app/assets/stylesheets/application.css
|
262
|
+
- spec/dummy/app/controllers/application_controller.rb
|
263
|
+
- spec/dummy/app/helpers/application_helper.rb
|
264
|
+
- spec/dummy/app/views/layouts/application.html.erb
|
265
|
+
- spec/dummy/config/application.rb
|
266
|
+
- spec/dummy/config/boot.rb
|
267
|
+
- spec/dummy/config/database.yml
|
268
|
+
- spec/dummy/config/environment.rb
|
269
|
+
- spec/dummy/config/environments/development.rb
|
270
|
+
- spec/dummy/config/environments/production.rb
|
271
|
+
- spec/dummy/config/environments/test.rb
|
272
|
+
- spec/dummy/config/initializers/backtrace_silencers.rb
|
273
|
+
- spec/dummy/config/initializers/inflections.rb
|
274
|
+
- spec/dummy/config/initializers/mime_types.rb
|
275
|
+
- spec/dummy/config/initializers/secret_token.rb
|
276
|
+
- spec/dummy/config/initializers/session_store.rb
|
277
|
+
- spec/dummy/config/initializers/wrap_parameters.rb
|
278
|
+
- spec/dummy/config/locales/en.yml
|
279
|
+
- spec/dummy/config/routes.rb
|
280
|
+
- spec/dummy/config.ru
|
281
|
+
- spec/dummy/db/test.sqlite3
|
282
|
+
- spec/dummy/public/404.html
|
283
|
+
- spec/dummy/public/422.html
|
284
|
+
- spec/dummy/public/500.html
|
285
|
+
- spec/dummy/public/favicon.ico
|
286
|
+
- spec/dummy/Rakefile
|
287
|
+
- spec/dummy/README.rdoc
|
288
|
+
- spec/dummy/script/rails
|
289
|
+
- spec/factories/stripe_invoice_invoices_factory.rb
|
290
|
+
- spec/spec_helper.rb
|
291
|
+
- spec/support/vcr_setup.rb
|
data/test/stripe_invoice_test.rb
DELETED
data/test/test_helper.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# Configure Rails Environment
|
2
|
-
ENV["RAILS_ENV"] = "test"
|
3
|
-
|
4
|
-
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
5
|
-
require "rails/test_help"
|
6
|
-
|
7
|
-
Rails.backtrace_cleaner.remove_silencers!
|
8
|
-
|
9
|
-
# Load support files
|
10
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
11
|
-
|
12
|
-
# Load fixtures from the engine
|
13
|
-
if ActiveSupport::TestCase.method_defined?(:fixture_path=)
|
14
|
-
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
|
15
|
-
end
|