start testing the paypal workflow.

This commit is contained in:
Shane Kilkelly 2016-06-27 16:34:00 +01:00
parent 3bf8da3e83
commit 709f8f2bea
2 changed files with 253 additions and 153 deletions

View file

@ -18,160 +18,178 @@ module.exports = RecurlyWrapper =
resultString += "</billing_info>\n"
return resultString
_paypal:
checkAccountExists: (cache, next) ->
user = cache.user
recurly_token_id = cache.recurly_token_id
subscriptionDetails = cache.subscriptionDetails
logger.log {user_id: user._id, recurly_token_id}, "checking if recurly account exists for user"
RecurlyWrapper.apiRequest({
url: "accounts/#{user._id}"
method: "GET"
}, (error, response, responseBody) ->
if error
if response.statusCode == 404 # actually not an error in this case, just no existing account
cache.userExists = false
return next(null, cache)
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while checking account"
return next(error)
logger.log {user_id: user._id, recurly_token_id}, "user appears to exist in recurly"
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error parsing account"
return next(err)
cache.account = account
return next(null, cache)
)
createAccount: (cache, next) ->
user = cache.user
recurly_token_id = cache.recurly_token_id
subscriptionDetails = cache.subscriptionDetails
if cache.userExists
logger.log {user_id: user._id, recurly_token_id}, "user already exists in recurly"
return next(null, cache)
logger.log {user_id: user._id, recurly_token_id}, "creating user in recurly"
address = subscriptionDetails.address
if !address
return next(new Error('no address in subscriptionDetails at createAccount stage'))
requestBody = """
<account>
<account_code>#{user._id}</account_code>
<email>#{user.email}</email>
<first_name>#{user.first_name}</first_name>
<last_name>#{user.last_name}</last_name>
<address>
<address1>#{address.address1}</address1>
<address2>#{address.address2}</address2>
<city>#{address.city || ''}</city>
<state>#{address.state || ''}</state>
<zip>#{address.zip || ''}</zip>
<country>#{address.country}</country>
</address>
</account>
"""
RecurlyWrapper.apiRequest({
url : "accounts"
method : "POST"
body : requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while creating account"
return next(error)
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error creating account"
return next(err)
cache.account = account
return next(null, cache)
)
createBillingInfo: (cache, next) ->
user = cache.user
recurly_token_id = cache.recurly_token_id
subscriptionDetails = cache.subscriptionDetails
logger.log {user_id: user._id, recurly_token_id}, "creating billing info in recurly"
accountCode = cache?.account?.account_code
if !accountCode
return next(new Error('no account code at createBillingInfo stage'))
requestBody = """
<billing_info>
<token_id>#{recurly_token_id}</token_id>
</billing_info>
"""
RecurlyWrapper.apiRequest({
url: "accounts/#{accountCode}/billing_info"
method: "POST"
body: requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while creating billing info"
return next(error)
RecurlyWrapper._parseBillingInfoXml responseBody, (err, billingInfo) ->
if err
logger.error {err, user_id: user._id, accountCode, recurly_token_id}, "error creating billing info"
return next(err)
cache.billingInfo = billingInfo
return next(null, cache)
)
setAddress: (cache, next) ->
user = cache.user
recurly_token_id = cache.recurly_token_id
subscriptionDetails = cache.subscriptionDetails
logger.log {user_id: user._id, recurly_token_id}, "setting billing address in recurly"
accountCode = cache?.account?.account_code
if !accountCode
return next(new Error('no account code at setAddress stage'))
address = subscriptionDetails.address
if !address
return next(new Error('no address in subscriptionDetails at setAddress stage'))
requestBody = RecurlyWrapper._addressToXml(address)
RecurlyWrapper.apiRequest({
url: "accounts/#{accountCode}/billing_info"
method: "PUT"
body: requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while setting address"
return next(error)
RecurlyWrapper._parseBillingInfoXml responseBody, (err, billingInfo) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error updating billing info"
return next(err)
cache.billingInfo = billingInfo
return next(null, cache)
)
createSubscription: (cache, next) ->
user = cache.user
recurly_token_id = cache.recurly_token_id
subscriptionDetails = cache.subscriptionDetails
logger.log {user_id: user._id, recurly_token_id}, "creating subscription in recurly"
requestBody = """
<subscription>
<plan_code>#{subscriptionDetails.plan_code}</plan_code>
<currency>#{subscriptionDetails.currencyCode}</currency>
<coupon_code>#{subscriptionDetails.coupon_code}</coupon_code>
<account>
<account_code>#{user._id}</account_code>
</account>
</subscription>
""" # TODO: check account details and billing
RecurlyWrapper.apiRequest({
url : "subscriptions"
method : "POST"
body : requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while creating subscription"
return next(error)
RecurlyWrapper._parseSubscriptionXml responseBody, (err, subscription) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error creating subscription"
return next(err)
cache.subscription = subscription
return next(null, cache)
)
_createPaypalSubscription: (user, subscriptionDetails, recurly_token_id, callback) ->
logger.log {user_id: user._id, recurly_token_id}, "starting process of creating paypal subscription"
cache = {user, recurly_token_id, subscriptionDetails}
Async.waterfall([
(next) -> # check if account exists
logger.log {user_id: user._id, recurly_token_id}, "checking if recurly account exists for user"
RecurlyWrapper.apiRequest({
url: "accounts/#{user._id}"
method: "GET"
}, (error, response, responseBody) ->
result = {userExists: true}
if error
if response.statusCode == 404 # actually not an error in this case, just no existing account
result.userExists = false
return next(null, result)
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while checking account"
return next(error)
logger.log {user_id: user._id, recurly_token_id}, "user appears to exist in recurly"
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error parsing account"
return next(err)
result.account = account
return next(null, result)
)
, (result, next) -> # create account
if result.userExists
logger.log {user_id: user._id, recurly_token_id}, "user already exists in recurly"
return next(null, result)
logger.log {user_id: user._id, recurly_token_id}, "creating user in recurly"
address = subscriptionDetails.address
if !address
return next(new Error('no address in subscriptionDetails at createAccount stage'))
requestBody = """
<account>
<account_code>#{user._id}</account_code>
<email>#{user.email}</email>
<first_name>#{user.first_name}</first_name>
<last_name>#{user.last_name}</last_name>
<address>
<address1>#{address.address1}</address1>
<address2>#{address.address2}</address2>
<city>#{address.city || ''}</city>
<state>#{address.state || ''}</state>
<zip>#{address.zip || ''}</zip>
<country>#{address.country}</country>
</address>
</account>
"""
RecurlyWrapper.apiRequest({
url : "accounts"
method : "POST"
body : requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while creating account"
return next(error)
RecurlyWrapper._parseAccountXml responseBody, (err, account) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error creating account"
return next(err)
result.account = account
return next(null, result)
)
, (result, next) -> # create billing info
logger.log {user_id: user._id, recurly_token_id}, "creating billing info in recurly"
accountCode = result?.account?.account_code
if !accountCode
return next(new Error('no account code at createBillingInfo stage'))
requestBody = """
<billing_info>
<token_id>#{recurly_token_id}</token_id>
</billing_info>
"""
RecurlyWrapper.apiRequest({
url: "accounts/#{accountCode}/billing_info"
method: "POST"
body: requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while creating billing info"
return next(error)
RecurlyWrapper._parseBillingInfoXml responseBody, (err, billingInfo) ->
if err
logger.error {err, user_id: user._id, accountCode, recurly_token_id}, "error creating billing info"
return next(err)
result.billingInfo = billingInfo
return next(null, result)
)
, (result, next) -> # set address
logger.log {user_id: user._id, recurly_token_id}, "setting billing address in recurly"
accountCode = result?.account?.account_code
if !accountCode
return next(new Error('no account code at setAddress stage'))
address = subscriptionDetails.address
if !address
return next(new Error('no address in subscriptionDetails at setAddress stage'))
requestBody = RecurlyWrapper._addressToXml(address)
RecurlyWrapper.apiRequest({
url: "accounts/#{accountCode}/billing_info"
method: "PUT"
body: requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while setting address"
return next(error)
RecurlyWrapper._parseBillingInfoXml responseBody, (err, billingInfo) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error updating billing info"
return next(err)
result.billingInfo = billingInfo
return next(null, result)
)
, (result, next) -> # create subscription
logger.log {user_id: user._id, recurly_token_id}, "creating subscription in recurly"
requestBody = """
<subscription>
<plan_code>#{subscriptionDetails.plan_code}</plan_code>
<currency>#{subscriptionDetails.currencyCode}</currency>
<coupon_code>#{subscriptionDetails.coupon_code}</coupon_code>
<account>
<account_code>#{user._id}</account_code>
</account>
</subscription>
""" # TODO: check account details and billing
RecurlyWrapper.apiRequest({
url : "subscriptions"
method : "POST"
body : requestBody
}, (error, response, responseBody) =>
if error
logger.error {error, user_id: user._id, recurly_token_id}, "error response from recurly while creating subscription"
return next(error)
RecurlyWrapper._parseSubscriptionXml responseBody, (err, subscription) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error creating subscription"
return next(err)
result.subscription = subscription
return next(null, result)
)
], (err, result) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error in paypal subscription creation process"
return callback(err)
if !result.subscription
err = new Error('no subscription object in result')
logger.error {err, user_id: user._id, recurly_token_id}, "error in paypal subscription creation process"
return callback(err)
logger.log {user_id: user._id, recurly_token_id}, "done creating paypal subscription for user"
callback(null, result.subscription)
Async.apply(RecurlyWrapper._paypal.checkAccountExists, cache),
RecurlyWrapper._paypal.createAccount,
RecurlyWrapper._paypal.createBillingInfo,
RecurlyWrapper._paypal.setAddress,
RecurlyWrapper._paypal.createSubscription,
], (err, result) ->
if err
logger.error {err, user_id: user._id, recurly_token_id}, "error in paypal subscription creation process"
return callback(err)
if !result.subscription
err = new Error('no subscription object in result')
logger.error {err, user_id: user._id, recurly_token_id}, "error in paypal subscription creation process"
return callback(err)
logger.log {user_id: user._id, recurly_token_id}, "done creating paypal subscription for user"
callback(null, result.subscription)
)
_createCreditCardSubscription: (user, subscriptionDetails, recurly_token_id, callback) ->

View file

@ -516,6 +516,16 @@ describe "RecurlyWrapper", ->
expect(sub).to.equal @subscription
done()
it 'should call apiRequest', (done) ->
@call (err, sub) =>
@apiRequest.callCount.should.equal 1
done()
it 'should call _parseSubscriptionXml', (done) ->
@call (err, sub) =>
@_parseSubscriptionXml.callCount.should.equal 1
done()
describe 'when api request produces an error', ->
beforeEach ->
@ -526,6 +536,16 @@ describe "RecurlyWrapper", ->
expect(err).to.be.instanceof Error
done()
it 'should call apiRequest', (done) ->
@call (err, sub) =>
@apiRequest.callCount.should.equal 1
done()
it 'should not _parseSubscriptionXml', (done) ->
@call (err, sub) =>
@_parseSubscriptionXml.callCount.should.equal 0
done()
describe 'when parse xml produces an error', ->
beforeEach ->
@ -539,7 +559,69 @@ describe "RecurlyWrapper", ->
describe '_createPaypalSubscription', ->
beforeEach ->
@checkAccountExists = sinon.stub(@RecurlyWrapper._paypal, 'checkAccountExists')
@createAccount = sinon.stub(@RecurlyWrapper._paypal, 'createAccount')
@createBillingInfo = sinon.stub(@RecurlyWrapper._paypal, 'createBillingInfo')
@setAddress = sinon.stub(@RecurlyWrapper._paypal, 'setAddress')
@createSubscription = sinon.stub(@RecurlyWrapper._paypal, 'createSubscription')
@user =
_id: 'some_id'
email: 'user@example.com'
@subscriptionDetails =
currencyCode: "EUR"
plan_code: "some_plan_code"
coupon_code: ""
isPaypal: true
address:
address1: "addr_one"
address2: "addr_two"
country: "some_country"
state: "some_state"
zip: "some_zip"
@subscription = {}
@recurly_token_id = "a-token-id"
describe 'when all goes well', ->
# set up data callbacks
user = @user
subscriptionDetails = @subscriptionDetails
recurly_token_id = @recurly_token_id
beforeEach ->
@checkAccountExists.callsArgWith(1, null,
{user, subscriptionDetails, recurly_token_id,
userExists: false, account: {accountCode: 'xx'}}
)
@createAccount.callsArgWith(1, null,
{user, subscriptionDetails, recurly_token_id,
userExists: false, account: {accountCode: 'xx'}}
)
@createBillingInfo.callsArgWith(1, null,
{user, subscriptionDetails, recurly_token_id,
userExists: false, account: {accountCode: 'xx'}, billingInfo: {token_id: 'abc'}}
)
@setAddress.callsArgWith(1, null,
{user, subscriptionDetails, recurly_token_id,
userExists: false, account: {accountCode: 'xx'}, billingInfo: {token_id: 'abc'}}
)
@createSubscription.callsArgWith(1, null,
{user, subscriptionDetails, recurly_token_id,
userExists: false, account: {accountCode: 'xx'}, billingInfo: {token_id: 'abc'}, subscription: {}}
)
@call = (callback) =>
@RecurlyWrapper._createPaypalSubscription @user, @subscriptionDetails, @recurly_token_id, callback
afterEach ->
@checkAccountExists.restore()
@createAccount.restore()
@createBillingInfo.restore()
@setAddress.restore()
@createSubscription.restore()
it 'should not produce an error', (done) ->
@call (err, sub) =>
expect(err).to.not.be.instanceof Error
done()