Display Pricing Exceptions on Subscription Dashboard (#1720)

Display Pricing Exceptions on Subscription Dashboard

GitOrigin-RevId: 31de89824db70b7af1f8704e6da592064ce44bfd
This commit is contained in:
Timothée Alby 2019-04-23 10:21:00 -04:00 committed by sharelatex
parent 44ba16bb7c
commit 85e7f688d5
8 changed files with 118 additions and 4 deletions

View file

@ -321,6 +321,27 @@ module.exports = RecurlyWrapper =
RecurlyWrapper._parseAccountXml body, callback
)
getAccountActiveCoupons: (accountId, callback) ->
RecurlyWrapper.apiRequest({
url: "accounts/#{accountId}/redemptions"
}, (error, response, body) =>
return callback(error) if error?
RecurlyWrapper._parseRedemptionsXml body, (error, redemptions) ->
return callback(error) if error?
activeRedemptions = redemptions.filter (redemption) ->
redemption.state == 'active'
couponCodes = activeRedemptions.map (redemption) ->
redemption.coupon_code
Async.map couponCodes, RecurlyWrapper.getCoupon, (error, coupons) ->
return callback(error) if error?
callback(null, coupons)
)
getCoupon: (couponCode, callback) ->
opts = { url: "coupons/#{couponCode}" }
RecurlyWrapper.apiRequest opts, (error, response, body) ->
RecurlyWrapper._parseCouponXml body, callback
getBillingInfo: (accountId, callback)->
RecurlyWrapper.apiRequest({
url: "accounts/#{accountId}/billing_info"
@ -465,6 +486,12 @@ module.exports = RecurlyWrapper =
_parseBillingInfoXml: (xml, callback) ->
RecurlyWrapper._parseXmlAndGetAttribute xml, "billing_info", callback
_parseRedemptionsXml: (xml, callback) ->
RecurlyWrapper._parseXmlAndGetAttribute xml, "redemptions", callback
_parseCouponXml: (xml, callback) ->
RecurlyWrapper._parseXmlAndGetAttribute xml, "coupon", callback
_parseXmlAndGetAttribute: (xml, attribute, callback) ->
RecurlyWrapper._parseXml xml, (error, data) ->
return callback(error) if error?
@ -505,6 +532,7 @@ module.exports = RecurlyWrapper =
parser = new xml2js.Parser(
explicitRoot : true
explicitArray : false
emptyTag: ''
)
parser.parseString xml, (error, data) ->
return callback(error) if error?

View file

@ -150,7 +150,7 @@ module.exports = SubscriptionController =
return res.redirect '/user/subscription/plans'
res.render "subscriptions/successful_subscription",
title: "thank_you"
subscription:personalSubscription
personalSubscription: personalSubscription
cancelSubscription: (req, res, next) ->
user = AuthenticationController.getSessionUser(req)

View file

@ -34,6 +34,11 @@ module.exports =
return cb(null, null)
RecurlyWrapper.getSubscription personalSubscription.recurlySubscription_id, includeAccount: true, cb
]
recurlyCoupons: ['recurlySubscription', (cb, {recurlySubscription}) ->
return cb(null, null) if !recurlySubscription
accountId = recurlySubscription.account.account_code
RecurlyWrapper.getAccountActiveCoupons accountId, cb
]
plan: ['personalSubscription', (cb, {personalSubscription}) ->
return cb() if !personalSubscription?
plan = PlansLocator.findLocalPlanInSettings(personalSubscription.planCode)
@ -65,6 +70,7 @@ module.exports =
managedPublishers,
v1SubscriptionStatus,
recurlySubscription,
recurlyCoupons,
plan
} = results
memberGroupSubscriptions ?= []
@ -72,6 +78,7 @@ module.exports =
confirmedMemberInstitutions ?= []
managedInstitutions ?= []
v1SubscriptionStatus ?= {}
recurlyCoupons ?= []
if personalSubscription?.toObject?
@ -93,6 +100,7 @@ module.exports =
state: recurlySubscription.state
trialEndsAtFormatted: SubscriptionFormatters.formatDate(recurlySubscription?.trial_ends_at)
trial_ends_at: recurlySubscription.trial_ends_at
activeCoupons: recurlyCoupons
}
for memberGroupSubscription in memberGroupSubscriptions

View file

@ -0,0 +1,9 @@
p
i * !{translate("subject_to_additional_vat")}
if (personalSubscription.recurly.activeCoupons.length > 0)
i * !{translate("coupons_not_included")}:
ul
each coupon in personalSubscription.recurly.activeCoupons
li
i= coupon.description || coupon.name

View file

@ -13,6 +13,7 @@ div(ng-controller="RecurlySubscriptionController")
-if (personalSubscription.recurly.trialEndsAtFormatted && personalSubscription.recurly.trial_ends_at > Date.now())
p You're on a free trial which ends on <strong ng-non-bindable>#{personalSubscription.recurly.trialEndsAtFormatted}</strong>
p !{translate("next_payment_of_x_collectected_on_y", {paymentAmmount:"<strong>" + personalSubscription.recurly.price + "</strong>", collectionDate:"<strong>" + personalSubscription.recurly.nextPaymentDueAt + "</strong>"})}
include ./../_price_exceptions
p.pull-right
p
a(href=personalSubscription.recurly.billingDetailsLink, target="_blank").btn.btn-info #{translate("update_your_billing_details")}

View file

@ -9,14 +9,15 @@ block content
.page-header
h2 #{translate("thanks_for_subscribing")}
.alert.alert-success
p !{translate("next_payment_of_x_collectected_on_y", {paymentAmmount:"<strong>"+subscription.recurly.price+"</strong>", collectionDate:"<strong>"+subscription.recurly.nextPaymentDueAt+"</strong>"})}
p !{translate("next_payment_of_x_collectected_on_y", {paymentAmmount:"<strong>"+personalSubscription.recurly.price+"</strong>", collectionDate:"<strong>"+personalSubscription.recurly.nextPaymentDueAt+"</strong>"})}
include ./_price_exceptions
p #{translate("to_modify_your_subscription_go_to")}
a(href="/user/subscription") #{translate("manage_subscription")}.
p
- if (subscription.groupPlan == true)
- if (personalSubscription.groupPlan == true)
a.btn.btn-success.btn-large(href="/subscription/group") #{translate("add_your_first_group_member_now")}
p.letter-from-founders
p #{translate("thanks_for_subscribing_you_help_sl", {planName:subscription.plan.name})}
p #{translate("thanks_for_subscribing_you_help_sl", {planName:personalSubscription.plan.name})}
p #{translate("need_anything_contact_us_at")}
a(href=`mailto:${settings.adminEmail}`, ng-non-bindable) #{settings.adminEmail}
| .

View file

@ -42,6 +42,11 @@ describe 'Subscriptions', ->
account_id: 'mock-account-id',
trial_ends_at: new Date(2018, 6, 7)
}
MockRecurlyApi.coupons = @coupons = {
'test-coupon-1': { description: 'Test Coupon 1' }
'test-coupon-2': { description: 'Test Coupon 2' }
'test-coupon-3': { name: 'TestCoupon3' }
}
Subscription.create {
admin_id: @user._id,
manager_ids: [@user._id],
@ -57,6 +62,8 @@ describe 'Subscriptions', ->
after (done) ->
MockRecurlyApi.accounts = {}
MockRecurlyApi.subscriptions = {}
MockRecurlyApi.coupons = {}
MockRecurlyApi.redemptions = {}
Subscription.remove {
admin_id: @user._id
}, done
@ -68,6 +75,7 @@ describe 'Subscriptions', ->
expect(subscription.planCode).to.equal 'collaborator'
expect(subscription.recurly).to.exist
expect(subscription.recurly).to.deep.equal {
"activeCoupons": []
"billingDetailsLink": "https://test.recurly.com/account/billing_info/edit?ht=mock-login-token"
"currency": "GBP"
"nextPaymentDueAt": "5th May 2018"
@ -82,6 +90,30 @@ describe 'Subscriptions', ->
it 'should return no memberGroupSubscriptions', ->
expect(@data.memberGroupSubscriptions).to.deep.equal []
it 'should include redeemed coupons', (done) ->
MockRecurlyApi.redemptions['mock-account-id'] = [
{ state: 'active', coupon_code: 'test-coupon-1' }
{ state: 'inactive', coupon_code: 'test-coupon-2' }
{ state: 'active', coupon_code: 'test-coupon-3' }
]
# rebuild the view model with the redemptions
SubscriptionViewModelBuilder.buildUsersSubscriptionViewModel @user, (error, data) ->
expect(error).to.not.exist
expect(data.personalSubscription.recurly.activeCoupons).to.deep.equal [
{
coupon_code: 'test-coupon-1',
name: '',
description: 'Test Coupon 1'
}
{
coupon_code: 'test-coupon-3',
name: 'TestCoupon3',
description: ''
}
]
done()
describe 'when the user has a subscription without recurly', ->
before (done) ->
Subscription.create {

View file

@ -9,6 +9,10 @@ module.exports = MockRecurlyApi =
accounts: {}
redemptions: {}
coupons: {}
run: () ->
app.get '/subscriptions/:id', (req, res, next) =>
subscription = @subscriptions[req.params.id]
@ -36,10 +40,41 @@ module.exports = MockRecurlyApi =
else
res.send """
<account>
<account_code>#{req.params.id}</account_code>
<hosted_login_token>#{account.hosted_login_token}</hosted_login_token>
</account>
"""
app.get '/coupons/:code', (req, res, next) =>
coupon = @coupons[req.params.code]
if !coupon?
res.status(404).end()
else
res.send """
<coupon>
<coupon_code>#{req.params.code}</coupon_code>
<name>#{coupon.name or ''}</name>
<description>#{coupon.description or ''}</description>
</coupon>
"""
app.get '/accounts/:id/redemptions', (req, res, next) =>
redemptions = @redemptions[req.params.id] or []
redemptionsListXml = ''
for redemption in redemptions
redemptionsListXml += """
<redemption>
<state>#{redemption.state}</state>
<coupon_code>#{redemption.coupon_code}</coupon_code>
</redemption>
"""
res.send """
<redemptions type="array">
#{redemptionsListXml}
</redemptions>
"""
app.listen 6034, (error) ->
throw error if error?