Skip to content

Commit 8f45d3a

Browse files
committed
Merge pull request coderwall#240 from YaroSpace/bug_invoice_generation_#392
Bug invoice generation #392
2 parents 1084599 + 4bb774f commit 8f45d3a

29 files changed

+458
-60
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
.idea
1212
.sass-cache
1313
.vagrant
14-
.rspec
14+
.rspec-local
1515
.yardoc
1616
/.bundle
1717
/config/application.yml

.rspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
--require spec_helper
2+
--require turnip/rspec
23
--format Fuubar
34
--color
45
--profile

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,10 @@ group :test do
169169
# gem 'rspec-its'
170170
gem 'capybara'
171171
gem 'capybara-screenshot'
172+
gem 'turnip' # write rspec feature specs in cucumber style
172173
gem 'rack_session_access' # allows to set session from within Capybara
173174
gem 'poltergeist' # headless js driver for Capybara that uses phantomJs
175+
gem 'selenium-webdriver' # headfull js driver for Capybara
174176
gem 'codeclimate-test-reporter', require: false
175177
gem 'database_cleaner'
176178
gem 'fuubar', '2.0.0.rc1'

Gemfile.lock

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ GEM
137137
carrierwave (~> 0.5)
138138
celluloid (0.15.2)
139139
timers (~> 1.1.0)
140+
childprocess (0.5.5)
141+
ffi (~> 1.0, >= 1.0.11)
140142
choice (0.1.6)
141143
chronic (0.10.2)
142144
chunky_png (1.3.1)
@@ -277,6 +279,8 @@ GEM
277279
multi_json (~> 1.0)
278280
net-http-persistent (>= 2.7)
279281
net-http-pipeline
282+
gherkin (2.12.2)
283+
multi_json (~> 1.3)
280284
github-markdown (0.6.6)
281285
grackle (0.3.0)
282286
json
@@ -591,6 +595,7 @@ GEM
591595
ruby-progressbar (1.5.1)
592596
ruby_parser (3.6.2)
593597
sexp_processor (~> 4.1)
598+
rubyzip (1.1.6)
594599
safe_yaml (1.0.3)
595600
sanitize (3.0.0)
596601
crass (~> 0.2.0)
@@ -606,6 +611,11 @@ GEM
606611
faraday (~> 0.8, < 0.10)
607612
sax-machine (0.2.1)
608613
nokogiri (~> 1.6.0)
614+
selenium-webdriver (2.43.0)
615+
childprocess (~> 0.5)
616+
multi_json (~> 1.0)
617+
rubyzip (~> 1.0)
618+
websocket (~> 1.0)
609619
sexp_processor (4.4.4)
610620
shoulda-matchers (2.6.2)
611621
activesupport (>= 3.0.0)
@@ -686,6 +696,9 @@ GEM
686696
treetop (1.4.15)
687697
polyglot
688698
polyglot (>= 0.3.1)
699+
turnip (1.2.4)
700+
gherkin (>= 2.5)
701+
rspec (>= 2.14.0, < 4.0)
689702
tweet-button (0.1.0)
690703
twitter (5.5.1)
691704
addressable (~> 2.3)
@@ -813,6 +826,7 @@ DEPENDENCIES
813826
sanitize
814827
sass (~> 3.2.9)
815828
sass-rails (~> 3.2.6)
829+
selenium-webdriver
816830
shoulda-matchers
817831
sidekiq
818832
simple_form
@@ -829,6 +843,7 @@ DEPENDENCIES
829843
timecop
830844
tire
831845
travis
846+
turnip
832847
tweet-button
833848
twitter
834849
uglifier (>= 1.0.3)

app/controllers/accounts_controller.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,15 @@ def webhook
6262
end
6363

6464
def send_invoice
65-
@team = Team.find(params[:team_id])
66-
@team.account.send_invoice_for(1.month.ago)
67-
redirect_to teamname_path(slug: @team.slug), notice: "sent invoice for #{1.month.ago.strftime("%B")} to #{@team.account.admin.email}"
65+
team, period = Team.find(params[:team_id]), 1.month.ago
66+
67+
if team.account.send_invoice_for(period)
68+
flash[:notice] = "sent invoice for #{period.strftime("%B")} to #{team.account.admin.email}"
69+
else
70+
flash[:error] = 'There was an error in sending an invoice'
71+
end
72+
73+
redirect_to teamname_path(slug: team.slug)
6874
end
6975

7076
private

app/controllers/application_controller.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class ApplicationController < ActionController::Base
2121
after_action :record_visit
2222
after_action :record_location
2323

24+
rescue_from ActiveRecord::RecordNotFound, with: :render_404 unless Rails.env.production?
25+
rescue_from ActionController::RoutingError, with: :render_404 unless Rails.env.production?
26+
2427
protected
2528

2629
def apply_flash_message
@@ -179,9 +182,6 @@ def not_on_achievements?
179182
params[:controller] != 'achievements'
180183
end
181184

182-
rescue_from ActiveRecord::RecordNotFound, with: :render_404
183-
rescue_from ActionController::RoutingError, with: :render_404
184-
185185
def render_404
186186
render template: 'error/not_found', status: :not_found
187187
end

app/helpers/accounts_helper.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,17 @@ def monthly_plan_price(plan)
66
def purchased_plan(plan)
77
plan.nil? ? "Monthly" : plan.name
88
end
9+
10+
def card_for(customer)
11+
card = customer[:active_card] || customer[:cards].first
12+
end
13+
14+
def invoice_date(invoice)
15+
Time.at(invoice[:date]).to_date.to_formatted_s(:long_ordinal)
16+
end
17+
18+
def subscription_period_for(invoice, period)
19+
subscription_period = invoice[:lines][:data].first[:period][period]
20+
Time.at(subscription_period).to_date.to_formatted_s(:long_ordinal)
21+
end
922
end

app/mailers/notifier_mailer.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class NotifierMailer < ActionMailer::Base
55
add_template_helper(UsersHelper)
66
add_template_helper(ProtipsHelper)
77
add_template_helper(ApplicationHelper)
8+
add_template_helper(AccountsHelper)
89

910
layout 'email', except: [:weekly_digest, :alert_admin]
1011

app/views/notifier_mailer/invoice.html.haml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
%tr
22
%td.main-content-grey{:style => "padding: 30px 60px; background:#ffffff;font-family:'Helvetica Neue','Helvetica','Arial','sans-serif';"}
33
%p{:style => "font-size: 16px; font-family:'Helvetica Neue','Helvetica','Arial','sans-serif'; margin-bottom: 10px;"}
4-
==Your card has ending in #{@customer[:active_card][:last4]} been charged
4+
="Your card ending in #{card_for(@customer)[:last4]} has been charged"
55
%table{:style => "width:600"}
66
%tr
77
%td
8-
== Bill Date: #{Time.at(@invoice[:date]).strftime("%B %d, %Y")}
8+
== Bill Date: #{invoice_date(@invoice)}
99
%tr
1010
%td
1111
%tr
@@ -20,7 +20,7 @@
2020
%tr
2121
%td
2222
Duration:
23-
==#{Time.at(@invoice[:lines][:subscriptions].first[:period][:start]).strftime("%B %d, %Y")}-#{Time.at(@invoice[:lines][:subscriptions].first[:period][:end]).strftime("%B %d, %Y")}
23+
==#{subscription_period_for(@invoice, :start)}-#{subscription_period_for(@invoice, :end)}
2424
%td
2525
Description:
2626
Enhanced Team Profile (4 job posts anytime)

app/views/subscription_mailer/team_upgrade.html.haml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,3 @@
1616
%p{:style => "font-size: 14px; margin: 0; font-family:'Helvetica Neue','Helvetica','Arial','sans-serif';"}
1717
If you have any questions or concerns about your account, please contact us:
1818
=mail_to('support@coderwall.com', nil, :style => "color:3D8DCC;")
19-
20-
21-

app/views/subscription_mailer/team_upgrade.text.erb

Lines changed: 0 additions & 13 deletions
This file was deleted.

app/views/teams/premium.html.haml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
%ul.legend
4646
%li.team-visitors
4747
=link_to 'Visitors', visitors_team_path(@team)
48-
-if is_admin?
48+
-if is_admin? && @team.account
4949
%li.send-invoice
5050
=link_to 'Send Invoice', send_invoice_team_account_path(@team), :method => :post
5151

config/environments/test.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313

1414
# Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
1515
config.assets.allow_debugging = true
16+
config.middleware.use RackSessionAccess::Middleware # allows to set session from within Capybara
1617

17-
config.middleware.use RackSessionAccess::Middleware # alloes to set session from within Capybara
18-
19-
Rails.logger = Logger.new(STDOUT)
20-
Rails.logger.level = Logger::DEBUG # provides more verbose output when testing with headless browsers in case of errors
18+
Rails.logger = Logger.new(STDOUT) # provides more verbose output when testing with headless browsers in case of errors
19+
Rails.logger.level = Logger::DEBUG
2120
end

spec/controllers/accounts_controller_spec.rb

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
RSpec.describe AccountsController, :type => :controller do
2-
let(:team) { Fabricate(:team) }
2+
let(:team) { Fabricate(:team, account: nil) }
33
let(:plan) { Plan.create(amount: 20000, interval: Plan::MONTHLY, name: 'Monthly') }
44
let(:current_user) { Fabricate(:user) }
55

@@ -30,4 +30,38 @@ def valid_params
3030

3131
end
3232
end
33+
34+
describe '#send_inovice' do
35+
before do
36+
team.account = Account.new
37+
38+
allow(Team).to receive(:find) { team }
39+
allow(team.account).to receive(:send_invoice_for) { true }
40+
allow(team.account).to receive(:admin) { current_user }
41+
42+
allow(Time).to receive(:current) { Date.parse('02/11/15').to_time } # so we do not bother with the time portion of the day
43+
end
44+
45+
it 'calls send_invoice for the last month' do
46+
expect(team.account).to receive(:send_invoice_for).with(Date.parse('02/10/15').to_time)
47+
get :send_invoice, id: '123'
48+
end
49+
50+
it 'displays success message' do
51+
get :send_invoice, id: '123'
52+
expect(flash[:notice]).to eq("sent invoice for October to #{current_user.email}")
53+
end
54+
55+
it 'redirects to team profile' do
56+
get :send_invoice, id: '123'
57+
expect(response).to redirect_to(teamname_path(slug: team.slug))
58+
end
59+
60+
it 'displays failure message' do
61+
allow(team.account).to receive(:send_invoice_for) { false }
62+
get :send_invoice, id: '123'
63+
expect(flash[:error]).to eq('There was an error in sending an invoice')
64+
end
65+
66+
end
3367
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
Fabricator(:account) do
2+
name 'test_account'
3+
admin_id 1
4+
stripe_card_token { "tok_14u7LDFs0zmMxCeEU3OGRUa0_#{rand(1000)}" }
5+
stripe_customer_token { "cus_54FsD2W2VkrKpW_#{rand(1000)}" }
26
end

spec/fabricators/plan_fabricator.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
Fabricator(:plan) do
2+
name { sequence(:name) { |i| "plan_no_#{i}" } }
3+
amount { rand * 100 }
24
end
35

46
# == Schema Information

spec/fabricators/team_fabricator.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Fabricator(:team) do
22
name { Faker::Company.name }
3-
end
3+
account { Fabricate.build(:account) }
4+
end

spec/features/steps/basic_steps.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
step 'I am logged in as :name with email :email' do |name, email|
2+
login_as(username: name, email: email, bypass_ui_login: true)
3+
@logged_in_user = User.where(username: name).first
4+
end
5+
6+
step 'I go/am to/on page for :pupropse' do |purpose|
7+
path = case purpose
8+
when 'team management' then team_path(@logged_in_user.reload.team)
9+
end
10+
11+
visit path
12+
end
13+
14+
step 'show me the page' do
15+
page.save_screenshot('tmp/screenshot.png', full: true)
16+
end
17+
18+
step 'I click :link_name' do |name|
19+
click_link name
20+
end
21+
22+
step 'I am an administrator' do
23+
@logged_in_user.admin = true
24+
@logged_in_user.save
25+
end
26+
27+
step 'I should see :text' do |text|
28+
expect(page).to have_content(text)
29+
end
30+
31+
step 'I should see:' do |table|
32+
table.hashes.each do |text|
33+
expect(page).to have_content(text.values.first)
34+
end
35+
end
36+
37+
step 'the last email should contain:' do |table|
38+
mail = ActionMailer::Base.deliveries.last
39+
40+
table.hashes.each do |text|
41+
expect(mail).to have_content(text.values.first)
42+
end
43+
end

spec/features/steps/team_steps.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
step 'a team :team_name exists' do |team_name|
2+
Fabricate(:team, name: team_name)
3+
end
4+
5+
step 'team :team_name is subscribed to plan :plan_name with card :card_no' do |team_name, plan_name, card_no|
6+
plan = Fabricate.build(:plan, name: plan_name)
7+
8+
stripe_plan = JSON.parse(File.read('./spec/fixtures/stripe/stripe_plan.json')).with_indifferent_access.tap do |h|
9+
h[:interval] = plan.interval
10+
h[:name] = plan.name
11+
h[:created] = plan.created_at
12+
h[:amount] = plan.amount
13+
h[:currency] = plan.currency
14+
h[:id] = plan.public_id
15+
end
16+
stub_request(:post, /api.stripe.com\/v1\/plans/).to_return(body: stripe_plan.to_json)
17+
18+
plan.save
19+
20+
team = Team.where(name: team_name).first
21+
team.account.plan_ids = [plan.id]
22+
team.save
23+
24+
stripe_customer = JSON.parse(File.read('./spec/fixtures/stripe/stripe_customer.json')).with_indifferent_access.tap do |h|
25+
h[:id] = team.account.stripe_customer_token
26+
h[:description] = "test@test.com for #{team_name}"
27+
h[:cards][:data].first[:last4] = card_no
28+
end
29+
stub_request(:get, /api.stripe.com\/v1\/customers\/#{team.account.stripe_customer_token}/).to_return(body: stripe_customer.to_json)
30+
end
31+
32+
step 'team :team_name has invoices with data:' do |team_name, table|
33+
team = Team.where(name: team_name).first
34+
data = table.rows_hash
35+
36+
stripe_invoices = JSON.parse(File.read('./spec/fixtures/stripe/stripe_invoices.json')).with_indifferent_access.tap do |h|
37+
h[:data].first[:date] = Date.parse(data['Date']).to_time.to_i
38+
h[:data].first[:lines][:data].first[:period][:start] = Date.parse(data['Start']).to_time.to_i
39+
h[:data].first[:lines][:data].first[:period][:end] = Date.parse(data['End']).to_time.to_i
40+
end
41+
stub_request(:get, /api.stripe.com\/v1\/invoices/).to_return(body: stripe_invoices.to_json)
42+
end
43+
44+
step 'I am member of team :team_name' do |team_name|
45+
team = Team.find_by(name: team_name)
46+
team.add_user(@logged_in_user)
47+
team.account.admin_id = @logged_in_user.id
48+
team.save
49+
end

0 commit comments

Comments
 (0)