stripe_invoice 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.project +14 -0
  4. data/Gemfile +31 -0
  5. data/Gemfile.lock +219 -0
  6. data/Rakefile +33 -32
  7. data/app/assets/images/stripe_invoice/.gitkeep +0 -0
  8. data/app/controllers/stripe_invoice/invoices_controller.rb +17 -42
  9. data/app/delayed_jobs/stripe_invoice/dj_tax_report.rb +73 -0
  10. data/app/helpers/stripe_invoice/application_helper.rb +7 -1
  11. data/app/helpers/stripe_invoice/invoices_helper.rb +1 -1
  12. data/app/helpers/stripe_invoice/tax_report_helper.rb +16 -0
  13. data/app/mailers/stripe_invoice/invoice_mailer.rb +35 -0
  14. data/app/models/stripe_invoice/charge.rb +79 -0
  15. data/app/views/stripe_invoice/invoice_mailer/new_invoice.text.erb +7 -0
  16. data/app/views/stripe_invoice/invoice_mailer/refund_invoice.text.erb +10 -0
  17. data/app/views/stripe_invoice/invoices/tax_report.pdf.prawn +38 -0
  18. data/config/initializers/stripe_event.rb +13 -0
  19. data/db/migrate/20150217040042_add_fields_to_invoice.rb +10 -0
  20. data/db/migrate/20150217203002_rename_invoices_to_charges.rb +9 -0
  21. data/lib/stripe/api_operations_list.rb +30 -0
  22. data/lib/stripe_invoice/renderer.rb +27 -0
  23. data/lib/stripe_invoice/version.rb +1 -1
  24. data/lib/stripe_invoice.rb +4 -30
  25. data/lib/tasks/stripe_invoice_tasks.rake +20 -0
  26. data/script/rails +8 -0
  27. data/spec/dummy/app/mailers/.gitkeep +0 -0
  28. data/spec/dummy/app/models/.gitkeep +0 -0
  29. data/spec/dummy/lib/assets/.gitkeep +0 -0
  30. data/spec/dummy/log/.gitkeep +0 -0
  31. data/spec/fixtures/stripe_invoice/invoice_mailer/new_invoice +3 -0
  32. data/spec/mailers/stripe_invoice/invoice_mailer_spec.rb +20 -0
  33. data/stripe_invoice.gemspec +37 -0
  34. data/test/dummy/README.rdoc +261 -0
  35. data/test/dummy/Rakefile +7 -0
  36. data/test/dummy/app/assets/javascripts/application.js +15 -0
  37. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  38. data/test/dummy/app/controllers/application_controller.rb +3 -0
  39. data/test/dummy/app/helpers/application_helper.rb +2 -0
  40. data/test/dummy/app/mailers/.gitkeep +0 -0
  41. data/test/dummy/app/models/.gitkeep +0 -0
  42. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/test/dummy/config/application.rb +59 -0
  44. data/test/dummy/config/boot.rb +10 -0
  45. data/test/dummy/config/database.yml +25 -0
  46. data/test/dummy/config/environment.rb +5 -0
  47. data/test/dummy/config/environments/development.rb +37 -0
  48. data/test/dummy/config/environments/production.rb +67 -0
  49. data/test/dummy/config/environments/test.rb +37 -0
  50. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  51. data/test/dummy/config/initializers/inflections.rb +15 -0
  52. data/test/dummy/config/initializers/mime_types.rb +5 -0
  53. data/test/dummy/config/initializers/secret_token.rb +7 -0
  54. data/test/dummy/config/initializers/session_store.rb +8 -0
  55. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  56. data/test/dummy/config/locales/en.yml +5 -0
  57. data/test/dummy/config/routes.rb +4 -0
  58. data/test/dummy/config.ru +4 -0
  59. data/test/dummy/lib/assets/.gitkeep +0 -0
  60. data/test/dummy/log/.gitkeep +0 -0
  61. data/test/dummy/public/404.html +26 -0
  62. data/test/dummy/public/422.html +26 -0
  63. data/test/dummy/public/500.html +25 -0
  64. data/test/dummy/public/favicon.ico +0 -0
  65. data/test/dummy/script/rails +6 -0
  66. data/test/fixtures/stripe_invoice/invoices.yml +11 -0
  67. data/test/functional/stripe_invoice/invoices_controller_test.rb +9 -0
  68. data/test/integration/navigation_test.rb +10 -0
  69. data/test/stripe_invoice_test.rb +7 -0
  70. data/test/test_helper.rb +15 -0
  71. data/test/unit/helpers/stripe_invoice/invoices_helper_test.rb +6 -0
  72. data/test/unit/stripe_invoice/invoice_test.rb +9 -0
  73. metadata +142 -6
  74. data/app/models/stripe_invoice/invoice.rb +0 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20da253e1cd8256f9a83fdff32032f4e296e519c
4
- data.tar.gz: 31614a75ebf67a5426967dcb7f092d650172529b
3
+ metadata.gz: 4885d32ab6190113c39fb30c8ab1ce99904b4603
4
+ data.tar.gz: 204da69a615798863d6944c0001f14c2d5173feb
5
5
  SHA512:
6
- metadata.gz: 8c275a01506f4d2586a1b8c1f198c017d4fea5c8a788027a4876be3ac9e850294dc5906a2253437c5f6f2d90201f243ccd27dacd80b578278f141a9963a7f8b8
7
- data.tar.gz: 50bbbd8caed4779b00fe77994d2f12274199d5645c7d60a56b834bd9221f1ea5f511b805078aa8857256f7390837075226f77ec00d4baff577b2fa178bcae918
6
+ metadata.gz: 3623c343b700cc7caf4636198504d1b2dfd5e216874a30efa30aadc1397644565a7476f2a152a8c34b69971681e2f20c62aba134f63b9d44fae540b6350ef055
7
+ data.tar.gz: e7eef5100bf2191ed6708a750db875ec4304d892bb784888a51ba33d3c03e33231fb1b82093785448a704744ea2795c2b8bbeadce0d055f4f52729f062fb8d41
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/log/*.log
6
+ test/dummy/tmp/
7
+ test/dummy/.sass-cache
8
+ spec/dummy/log/*.log
9
+ spec/dummy/tmp/
10
+ spec/dummy/db/*.sqlite3
11
+ *.gem
data/.project ADDED
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>stripe_invoice</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ </buildSpec>
9
+ <natures>
10
+ <nature>com.aptana.projects.webnature</nature>
11
+ <nature>org.radrails.rails.core.railsnature</nature>
12
+ <nature>com.aptana.ruby.core.rubynature</nature>
13
+ </natures>
14
+ </projectDescription>
data/Gemfile ADDED
@@ -0,0 +1,31 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in stripe_invoice.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # jquery-rails is used by the dummy application
9
+ gem "jquery-rails"
10
+
11
+ gem 'stripe'
12
+ gem 'haml-rails'
13
+
14
+ gem 'prawn-rails'
15
+
16
+ group :development, :test do
17
+ gem "rspec-rails", "~> 2.12.2"
18
+ gem "factory_girl_rails", "~> 4.0"
19
+ gem 'pdf-inspector'
20
+ gem 'vcr'
21
+ gem 'webmock'
22
+ end
23
+
24
+
25
+ # Declare any dependencies that are still in development here instead of in
26
+ # your gemspec. These might include edge Rails or gems from your path or
27
+ # Git. Remember to move these dependencies to your gemspec before releasing
28
+ # your gem to rubygems.org.
29
+
30
+ # To use debugger
31
+ # gem 'debugger'
data/Gemfile.lock ADDED
@@ -0,0 +1,219 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ stripe_invoice (0.4.0)
5
+ delayed_job_active_record
6
+ haml-rails
7
+ prawn-rails
8
+ rails (~> 3.2.18)
9
+ stripe
10
+ stripe_event
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ Ascii85 (1.0.2)
16
+ actionmailer (3.2.18)
17
+ actionpack (= 3.2.18)
18
+ mail (~> 2.5.4)
19
+ actionpack (3.2.18)
20
+ activemodel (= 3.2.18)
21
+ activesupport (= 3.2.18)
22
+ builder (~> 3.0.0)
23
+ erubis (~> 2.7.0)
24
+ journey (~> 1.0.4)
25
+ rack (~> 1.4.5)
26
+ rack-cache (~> 1.2)
27
+ rack-test (~> 0.6.1)
28
+ sprockets (~> 2.2.1)
29
+ activemodel (3.2.18)
30
+ activesupport (= 3.2.18)
31
+ builder (~> 3.0.0)
32
+ activerecord (3.2.18)
33
+ activemodel (= 3.2.18)
34
+ activesupport (= 3.2.18)
35
+ arel (~> 3.0.2)
36
+ tzinfo (~> 0.3.29)
37
+ activeresource (3.2.18)
38
+ activemodel (= 3.2.18)
39
+ activesupport (= 3.2.18)
40
+ activesupport (3.2.18)
41
+ i18n (~> 0.6, >= 0.6.4)
42
+ multi_json (~> 1.0)
43
+ addressable (2.3.6)
44
+ afm (0.2.2)
45
+ arel (3.0.3)
46
+ bcrypt (3.1.9)
47
+ bluecloth (2.2.0)
48
+ builder (3.0.4)
49
+ capybara (2.4.4)
50
+ mime-types (>= 1.16)
51
+ nokogiri (>= 1.3.3)
52
+ rack (>= 1.0.0)
53
+ rack-test (>= 0.5.4)
54
+ xpath (~> 2.0)
55
+ coderay (1.1.0)
56
+ crack (0.4.2)
57
+ safe_yaml (~> 1.0.0)
58
+ delayed_job (4.0.6)
59
+ activesupport (>= 3.0, < 5.0)
60
+ delayed_job_active_record (4.0.3)
61
+ activerecord (>= 3.0, < 5.0)
62
+ delayed_job (>= 3.0, < 4.1)
63
+ devise (3.4.1)
64
+ bcrypt (~> 3.0)
65
+ orm_adapter (~> 0.1)
66
+ railties (>= 3.2.6, < 5)
67
+ responders
68
+ thread_safe (~> 0.1)
69
+ warden (~> 1.2.3)
70
+ diff-lcs (1.1.3)
71
+ erubis (2.7.0)
72
+ factory_girl (4.5.0)
73
+ activesupport (>= 3.0.0)
74
+ factory_girl_rails (4.5.0)
75
+ factory_girl (~> 4.5.0)
76
+ railties (>= 3.0.0)
77
+ haml (4.0.5)
78
+ tilt
79
+ haml-rails (0.4)
80
+ actionpack (>= 3.1, < 4.1)
81
+ activesupport (>= 3.1, < 4.1)
82
+ haml (>= 3.1, < 4.1)
83
+ railties (>= 3.1, < 4.1)
84
+ hashery (2.1.1)
85
+ hike (1.2.3)
86
+ i18n (0.6.9)
87
+ journey (1.0.4)
88
+ jquery-rails (3.1.0)
89
+ railties (>= 3.0, < 5.0)
90
+ thor (>= 0.14, < 2.0)
91
+ json (1.8.1)
92
+ koudoku (0.0.11)
93
+ bluecloth
94
+ rails
95
+ stripe
96
+ mail (2.5.4)
97
+ mime-types (~> 1.16)
98
+ treetop (~> 1.4.8)
99
+ method_source (0.8.2)
100
+ mime-types (1.25.1)
101
+ mini_portile (0.6.1)
102
+ multi_json (1.10.1)
103
+ nokogiri (1.6.4)
104
+ mini_portile (~> 0.6.0)
105
+ orm_adapter (0.5.0)
106
+ pdf-core (0.4.0)
107
+ pdf-inspector (1.2.0)
108
+ pdf-reader (~> 1.0)
109
+ pdf-reader (1.3.3)
110
+ Ascii85 (~> 1.0.0)
111
+ afm (~> 0.2.0)
112
+ hashery (~> 2.0)
113
+ ruby-rc4
114
+ ttfunk
115
+ polyglot (0.3.5)
116
+ prawn (1.3.0)
117
+ pdf-core (~> 0.4.0)
118
+ ttfunk (~> 1.4.0)
119
+ prawn-rails (0.1.0)
120
+ prawn
121
+ prawn-table
122
+ rails (>= 3.1.0)
123
+ prawn-table (0.2.1)
124
+ pry (0.10.1)
125
+ coderay (~> 1.1.0)
126
+ method_source (~> 0.8.1)
127
+ slop (~> 3.4)
128
+ rack (1.4.5)
129
+ rack-cache (1.2)
130
+ rack (>= 0.4)
131
+ rack-ssl (1.3.4)
132
+ rack
133
+ rack-test (0.6.2)
134
+ rack (>= 1.0)
135
+ rails (3.2.18)
136
+ actionmailer (= 3.2.18)
137
+ actionpack (= 3.2.18)
138
+ activerecord (= 3.2.18)
139
+ activeresource (= 3.2.18)
140
+ activesupport (= 3.2.18)
141
+ bundler (~> 1.0)
142
+ railties (= 3.2.18)
143
+ railties (3.2.18)
144
+ actionpack (= 3.2.18)
145
+ activesupport (= 3.2.18)
146
+ rack-ssl (~> 1.3.2)
147
+ rake (>= 0.8.7)
148
+ rdoc (~> 3.4)
149
+ thor (>= 0.14.6, < 2.0)
150
+ rake (10.3.2)
151
+ rdoc (3.12.2)
152
+ json (~> 1.4)
153
+ responders (1.1.1)
154
+ railties (>= 3.2, < 4.2)
155
+ rest-client (1.6.7)
156
+ mime-types (>= 1.16)
157
+ rspec-core (2.12.2)
158
+ rspec-expectations (2.12.1)
159
+ diff-lcs (~> 1.1.3)
160
+ rspec-mocks (2.12.2)
161
+ rspec-rails (2.12.2)
162
+ actionpack (>= 3.0)
163
+ activesupport (>= 3.0)
164
+ railties (>= 3.0)
165
+ rspec-core (~> 2.12.0)
166
+ rspec-expectations (~> 2.12.0)
167
+ rspec-mocks (~> 2.12.0)
168
+ ruby-rc4 (0.1.5)
169
+ safe_yaml (1.0.4)
170
+ slop (3.6.0)
171
+ sprockets (2.2.2)
172
+ hike (~> 1.2)
173
+ multi_json (~> 1.0)
174
+ rack (~> 1.0)
175
+ tilt (~> 1.1, != 1.3.0)
176
+ sqlite3 (1.3.10)
177
+ stripe (1.11.0)
178
+ json (~> 1.8.1)
179
+ mime-types (~> 1.25)
180
+ rest-client (~> 1.4)
181
+ stripe_event (1.4.0)
182
+ activesupport (>= 3.1)
183
+ stripe (~> 1.6)
184
+ thor (0.19.1)
185
+ thread_safe (0.3.4)
186
+ tilt (1.4.1)
187
+ treetop (1.4.15)
188
+ polyglot
189
+ polyglot (>= 0.3.1)
190
+ ttfunk (1.4.0)
191
+ tzinfo (0.3.42)
192
+ vcr (2.9.3)
193
+ warden (1.2.3)
194
+ rack (>= 1.0)
195
+ webmock (1.20.4)
196
+ addressable (>= 2.3.6)
197
+ crack (>= 0.3.2)
198
+ xpath (2.0.0)
199
+ nokogiri (~> 1.3)
200
+
201
+ PLATFORMS
202
+ ruby
203
+
204
+ DEPENDENCIES
205
+ capybara
206
+ devise
207
+ factory_girl_rails (~> 4.0)
208
+ haml-rails
209
+ jquery-rails
210
+ koudoku
211
+ pdf-inspector
212
+ prawn-rails
213
+ pry
214
+ rspec-rails (~> 2.12.2)
215
+ sqlite3
216
+ stripe
217
+ stripe_invoice!
218
+ vcr
219
+ webmock
data/Rakefile CHANGED
@@ -1,33 +1,34 @@
1
1
  #!/usr/bin/env rake
2
- begin
3
- require 'bundler/setup'
4
- rescue LoadError
5
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
- end
7
- begin
8
- require 'rdoc/task'
9
- rescue LoadError
10
- require 'rdoc/rdoc'
11
- require 'rake/rdoctask'
12
- RDoc::Task = Rake::RDocTask
13
- end
14
-
15
- RDoc::Task.new(:rdoc) do |rdoc|
16
- rdoc.rdoc_dir = 'rdoc'
17
- rdoc.title = 'StripeInvoice'
18
- rdoc.options << '--line-numbers'
19
- rdoc.rdoc_files.include('README.rdoc')
20
- rdoc.rdoc_files.include('lib/**/*.rb')
21
- end
22
-
23
- APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
- load 'rails/tasks/engine.rake'
25
-
26
- Bundler::GemHelper.install_tasks
27
-
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')
32
-
33
- task :default => :spec
2
+ require "bundler/gem_tasks"
3
+ # begin
4
+ # require 'bundler/setup'
5
+ # rescue LoadError
6
+ # puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ # end
8
+ # begin
9
+ # require 'rdoc/task'
10
+ # rescue LoadError
11
+ # require 'rdoc/rdoc'
12
+ # require 'rake/rdoctask'
13
+ # RDoc::Task = Rake::RDocTask
14
+ # end
15
+ #
16
+ # RDoc::Task.new(:rdoc) do |rdoc|
17
+ # rdoc.rdoc_dir = 'rdoc'
18
+ # rdoc.title = 'StripeInvoice'
19
+ # rdoc.options << '--line-numbers'
20
+ # rdoc.rdoc_files.include('README.rdoc')
21
+ # rdoc.rdoc_files.include('lib/**/*.rb')
22
+ # end
23
+ #
24
+ # APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
25
+ # load 'rails/tasks/engine.rake'
26
+ #
27
+ # Bundler::GemHelper.install_tasks
28
+ #
29
+ # require 'rspec/core'
30
+ # require 'rspec/core/rake_task'
31
+ # desc "Run all specs in spec directory (excluding plugin specs)"
32
+ # RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
33
+ #
34
+ # task :default => :spec
File without changes
@@ -4,59 +4,34 @@ require "prawn-rails"
4
4
  module StripeInvoice
5
5
  class InvoicesController < ApplicationController
6
6
 
7
+ before_filter :authorize_owner
8
+
7
9
  def index
8
- @owner = send("current_#{::Koudoku.subscriptions_owned_by}")
9
- redirect_to '/' unless @owner
10
-
11
10
  @subscription = @owner.subscription
12
- if @subscription
13
- # I know this looks silly, but Koudoku actually stores the customer's stripe_id
14
- # in the subscription model
15
- @stripe_charges = Stripe::Charge.all(
16
- :customer => @subscription.stripe_id,
17
- :limit => 100)
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
41
- end
42
- end # if subscription
43
11
 
44
- @invoices = Invoice.where({owner_id: @owner.id, parent_invoice_id: nil}).order('stripe_id, date DESC')
12
+ @invoices = Charge.where(owner_id: @owner.id).order('date DESC')
45
13
  end
46
14
 
47
15
  def show
48
- @owner = send("current_#{::Koudoku.subscriptions_owned_by}")
49
- redirect_to '/' unless @owner
50
-
51
- @invoice = Invoice.find(params[:id])
52
-
16
+ @invoice = Charge.find(params[:id])
17
+
53
18
  respond_to do |format|
54
19
  format.html {render layout: false}
55
20
  format.pdf
56
21
  end
57
22
  end
58
-
23
+
24
+ def tax_report(data)
25
+ @_response = ActionDispatch::Response.new
26
+ @data = data
27
+ render template: 'stripe_invoice/invoices/tax_report', :formats => [:pdf], :locals => {sicharges: data}
28
+ end
29
+
59
30
  private
31
+ def authorize_owner
32
+ @owner = send("current_#{::Koudoku.subscriptions_owned_by}")
33
+ redirect_to '/' unless @owner
34
+ end
60
35
 
61
36
  def generate_invoice(scharge, owner, scharge_invoice, scharge_refund=nil, parent_invoice=nil)
62
37
  amount, stripe_refund_id, parent_invoice_id = scharge_invoice[:total], nil, nil
@@ -66,7 +41,7 @@ module StripeInvoice
66
41
  parent_invoice_id = parent_invoice.id if parent_invoice.present?
67
42
  end
68
43
 
69
- Invoice.create({
44
+ Charge.create({
70
45
  stripe_id: scharge_invoice.id,
71
46
  owner_id: owner.id,
72
47
  date: scharge.created,
@@ -0,0 +1,73 @@
1
+ module StripeInvoice
2
+ class DJTaxReport
3
+ def initialize(year = 1.year.ago.year)
4
+ @year = year
5
+ end
6
+
7
+
8
+ def perform
9
+ puts "[DJTaxReport] computing tax report for #{@year}"
10
+
11
+ sicharges = StripeInvoice::Charge.where(
12
+ "date >= ? and date <= ?",
13
+ date_to_epoch("#{@year}-01-01"),
14
+ date_to_epoch("#{@year}-12-31"))
15
+
16
+ puts "[DJTaxReport] number of charges in year: #{sicharges.size}"
17
+ arr_data = []
18
+ sicharges.each do |charge|
19
+ owner = Koudoku.owner_class.find(charge.owner_id)
20
+
21
+ next unless owner # skip if we don't have an owner
22
+
23
+ data = {
24
+ charge: charge,
25
+ bt: Stripe::BalanceTransaction.retrieve(charge.indifferent_json[:balance_transaction]),
26
+ owner: owner
27
+ }
28
+ puts "[DJTaxReport] aggregating data #{charge.stripe_id}"
29
+ if charge.indifferent_json[:refunds].count > 0
30
+ arr_refunds = []
31
+ charge.indifferent_json[:refunds].each do |refund|
32
+ refd = {
33
+ refund: refund,
34
+ bt: Stripe::BalanceTransaction.retrieve(refund[:balance_transaction])
35
+ }
36
+ arr_refunds << refd
37
+ end
38
+
39
+ data[:refunds] = arr_refunds
40
+ #puts "[DJTaxReport] charge had refunds: #{arr_refunds}"
41
+ end # has refunds
42
+
43
+ arr_data << data
44
+ end
45
+
46
+ puts "[DJTaxReport] data collected; rendering view"
47
+ #res = InvoicesController.new.tax_report arr_data
48
+ res = Renderer.render template: "stripe_invoice/invoices/tax_report",
49
+ locals: {sicharges: arr_data, year: @year, totals: totals(arr_data)},
50
+ formats: [:pdf]
51
+
52
+ #InvoiceMailer.tax_report.deliver!
53
+ end
54
+
55
+
56
+ private
57
+ def date_to_epoch(date)
58
+ Date.strptime(date,"%Y-%m-%d").to_datetime.utc.to_i
59
+ end
60
+
61
+ def totals(sicharges)
62
+ result = {
63
+ transaction_volume: total_transaction_volume(sicharges),
64
+ }
65
+ end
66
+
67
+ include ActionView::Helpers::NumberHelper
68
+ def total_transaction_volume(sicharges)
69
+ number_to_currency(sicharges.inject(0) {|sum, hash_ch| sum + hash_ch[:bt][:amount]} / 100.0,
70
+ unit: "#{sicharges.first[:bt][:currency].upcase} ")
71
+ end
72
+ end
73
+ end
@@ -2,7 +2,13 @@ module StripeInvoice
2
2
  module ApplicationHelper
3
3
 
4
4
  def format_timestamp(timestamp)
5
- l(Time.at(timestamp).to_datetime, :format => :short_date)
5
+ dt = timestamp
6
+
7
+ unless timestamp.is_a? DateTime
8
+ dt = Time.at(timestamp).to_datetime
9
+ end
10
+
11
+ l(dt, :format => :short_date)
6
12
  end
7
13
 
8
14
  alias_method :ft, :format_timestamp
@@ -8,7 +8,7 @@ module StripeInvoice
8
8
  # assuming that all currencies are split into 100 parts is probably wrong
9
9
  # on an i18n scale but it works for USD, EUR and LBP
10
10
  # TODO fix this maybe?
11
- amount = amount / 100
11
+ amount = amount / 100.0
12
12
  options = {
13
13
  # use comma for euro
14
14
  separator: currency == 'EUR' ? ',' : '.',
@@ -0,0 +1,16 @@
1
+ module StripeInvoice
2
+ module TaxReportHelper
3
+
4
+ # takes a Stripe JSON hash and an attribute name and returns a
5
+ # nicely formatted string for that currency
6
+ def format_stripe_currency(obj, attr_sym = :amount)
7
+ number_to_currency(obj[attr_sym].to_f / 100, unit: "#{obj[:currency].upcase} ")
8
+ end
9
+
10
+
11
+ def format_billing_address(owner)
12
+ raise "You need to implement #billing_address on your subscription owner class" unless owner.respond_to? :billing_address
13
+ owner.billing_address
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module StripeInvoice
2
+ class InvoiceMailer < ActionMailer::Base
3
+
4
+ # Subject can be set in your I18n file at config/locales/en.yml
5
+ # with the following lookup:
6
+ #
7
+ # en.invoice_mailer.new_invoice.subject
8
+ #
9
+ def new_invoice(charge)
10
+ @charge = charge
11
+
12
+
13
+ mail subject: "new #{I18n.t("config.stripe_invoice.app_name")} invoice available", to: @charge.owner.email
14
+ end
15
+
16
+ def refund_invoice(charge)
17
+ @charge = charge
18
+
19
+ mail subject: "We refunded your #{I18n.t("config.stripe_invoice.app_name")} charge", to: @charge.owner.email
20
+ end
21
+
22
+
23
+ def tax_report
24
+ attachments['tax-report.pdf'] = {
25
+ content: File.read(::Rails.root.join('tmp', 'tax_report.pdf')),
26
+ mime_type: "application/pdf"
27
+ }
28
+
29
+ # sends the email to the default from address
30
+ addr_to = ActionMailer::Base.default[:from]
31
+ mail subject: "Tax report", to: addr_to
32
+ puts "[InvoiceMailer] tax report sent to #{addr_to}"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,79 @@
1
+ module StripeInvoice
2
+ class Charge < ActiveRecord::Base
3
+ attr_accessible :id, :invoice_number, :stripe_id, :json,
4
+ :owner_id, :date, :amount, :discount, :total, :subtotal, :period_start,
5
+ :period_end, :currency
6
+
7
+ alias_attribute :number, :invoice_number
8
+
9
+ serialize :json, JSON
10
+
11
+ def indifferent_json
12
+ @json ||= json.with_indifferent_access
13
+ end
14
+
15
+ def datetime
16
+ Time.at(date).to_datetime
17
+ end
18
+
19
+ def owner
20
+ @owner ||= Koudoku.owner_class.find(owner_id)
21
+ end
22
+
23
+ def refunds
24
+ indifferent_json[:refunds]
25
+ end
26
+
27
+ def total_refund
28
+ refunds.inject(0){ |total,refund| total + refund[:amount]}
29
+ end
30
+
31
+ # builds the invoice from the stripe CHARGE object
32
+ # OR updates the existing invoice if an invoice for that id exists
33
+ def self.create_from_stripe(stripe_charge)
34
+ charge = Charge.find_by_stripe_id(stripe_charge[:id])
35
+
36
+ raise "won't build for unpaid charges" unless stripe_charge.paid
37
+ # for existing invoices just update and be done
38
+ if charge.present?
39
+ charge.update_attribute(:json, stripe_charge)
40
+ return charge
41
+ end
42
+
43
+ owner = get_subscription_owner stripe_charge
44
+
45
+ return unless owner
46
+
47
+ stripe_invoice = Stripe::Invoice.retrieve stripe_charge[:invoice]
48
+ last_charge = Charge.last
49
+ new_charge_number = (last_charge ? (last_charge.id * 7) : 1).to_s.rjust(5, '0')
50
+
51
+ charge_date = Time.at(stripe_charge[:created]).utc.to_datetime
52
+
53
+ charge = Charge.create({
54
+ stripe_id: stripe_charge[:id],
55
+ owner_id: owner.id,
56
+ date: stripe_charge[:created],
57
+ amount: stripe_charge[:amount],
58
+ subtotal: stripe_invoice[:subtotal],
59
+ discount: stripe_invoice[:discount],
60
+ total: stripe_invoice[:total],
61
+ currency: stripe_invoice[:currency],
62
+ period_start: stripe_invoice[:period_start],
63
+ period_end: stripe_invoice[:period_end],
64
+ invoice_number: "#{charge_date.year}-#{new_charge_number}",
65
+ json: stripe_charge
66
+ })
67
+
68
+ puts "Charge saved: #{charge.id}"
69
+ end
70
+
71
+ private
72
+ def self.get_subscription_owner(stripe_charge)
73
+ # ::Subscription is generated by Koudoku, but lives in main_app
74
+ subscription = ::Subscription.find_by_stripe_id(stripe_charge.customer)
75
+ return nil if subscription.nil?
76
+ owner = subscription.subscription_owner
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,7 @@
1
+ Hi there,
2
+
3
+ There is a new invoice available for you here: <%= invoice_url(@charge, :format => :pdf)%>.
4
+
5
+ If you find anything wrong with the invoice, please reply to this email.
6
+
7
+ Cheers