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.
- checksums.yaml +4 -4
- data/.gitignore +11 -0
- data/.project +14 -0
- data/Gemfile +31 -0
- data/Gemfile.lock +219 -0
- data/Rakefile +33 -32
- data/app/assets/images/stripe_invoice/.gitkeep +0 -0
- data/app/controllers/stripe_invoice/invoices_controller.rb +17 -42
- data/app/delayed_jobs/stripe_invoice/dj_tax_report.rb +73 -0
- data/app/helpers/stripe_invoice/application_helper.rb +7 -1
- data/app/helpers/stripe_invoice/invoices_helper.rb +1 -1
- data/app/helpers/stripe_invoice/tax_report_helper.rb +16 -0
- data/app/mailers/stripe_invoice/invoice_mailer.rb +35 -0
- data/app/models/stripe_invoice/charge.rb +79 -0
- data/app/views/stripe_invoice/invoice_mailer/new_invoice.text.erb +7 -0
- data/app/views/stripe_invoice/invoice_mailer/refund_invoice.text.erb +10 -0
- data/app/views/stripe_invoice/invoices/tax_report.pdf.prawn +38 -0
- data/config/initializers/stripe_event.rb +13 -0
- data/db/migrate/20150217040042_add_fields_to_invoice.rb +10 -0
- data/db/migrate/20150217203002_rename_invoices_to_charges.rb +9 -0
- data/lib/stripe/api_operations_list.rb +30 -0
- data/lib/stripe_invoice/renderer.rb +27 -0
- data/lib/stripe_invoice/version.rb +1 -1
- data/lib/stripe_invoice.rb +4 -30
- data/lib/tasks/stripe_invoice_tasks.rake +20 -0
- data/script/rails +8 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/fixtures/stripe_invoice/invoice_mailer/new_invoice +3 -0
- data/spec/mailers/stripe_invoice/invoice_mailer_spec.rb +20 -0
- data/stripe_invoice.gemspec +37 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/fixtures/stripe_invoice/invoices.yml +11 -0
- data/test/functional/stripe_invoice/invoices_controller_test.rb +9 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/stripe_invoice_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/helpers/stripe_invoice/invoices_helper_test.rb +6 -0
- data/test/unit/stripe_invoice/invoice_test.rb +9 -0
- metadata +142 -6
- data/app/models/stripe_invoice/invoice.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4885d32ab6190113c39fb30c8ab1ce99904b4603
|
4
|
+
data.tar.gz: 204da69a615798863d6944c0001f14c2d5173feb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3623c343b700cc7caf4636198504d1b2dfd5e216874a30efa30aadc1397644565a7476f2a152a8c34b69971681e2f20c62aba134f63b9d44fae540b6350ef055
|
7
|
+
data.tar.gz: e7eef5100bf2191ed6708a750db875ec4304d892bb784888a51ba33d3c03e33231fb1b82093785448a704744ea2795c2b8bbeadce0d055f4f52729f062fb8d41
|
data/.gitignore
ADDED
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
require '
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
rdoc.
|
18
|
-
rdoc.
|
19
|
-
rdoc.
|
20
|
-
rdoc.rdoc_files.include('
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
require 'rspec/core
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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 =
|
12
|
+
@invoices = Charge.where(owner_id: @owner.id).order('date DESC')
|
45
13
|
end
|
46
14
|
|
47
15
|
def show
|
48
|
-
@
|
49
|
-
|
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
|
-
|
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
|
-
|
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
|