mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-16 02:52:31 -04:00
Merge pull request #2697 from overleaf/pr-add-vat-number
Add VAT number and company name to the payment form GitOrigin-RevId: 9ba2d7345f6f3cef1f7372e17c04243ab285e0bd
This commit is contained in:
parent
ff38ea9533
commit
7f13e258bb
5 changed files with 125 additions and 35 deletions
|
@ -86,7 +86,7 @@ module.exports = RecurlyWrapper = {
|
||||||
|
|
||||||
let address
|
let address
|
||||||
try {
|
try {
|
||||||
address = getAddressFromSubscriptionDetails(subscriptionDetails)
|
address = getAddressFromSubscriptionDetails(subscriptionDetails, false)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(error)
|
return next(error)
|
||||||
}
|
}
|
||||||
|
@ -173,25 +173,36 @@ module.exports = RecurlyWrapper = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
setAddress(cache, next) {
|
setAddressAndCompanyBillingInfo(cache, next) {
|
||||||
const { user } = cache
|
const { user } = cache
|
||||||
const { subscriptionDetails } = cache
|
const { subscriptionDetails } = cache
|
||||||
logger.log({ user_id: user._id }, 'setting billing address in recurly')
|
logger.log(
|
||||||
|
{ user_id: user._id },
|
||||||
|
'setting billing address and company info in recurly'
|
||||||
|
)
|
||||||
const accountCode = __guard__(
|
const accountCode = __guard__(
|
||||||
cache != null ? cache.account : undefined,
|
cache != null ? cache.account : undefined,
|
||||||
x1 => x1.account_code
|
x1 => x1.account_code
|
||||||
)
|
)
|
||||||
if (!accountCode) {
|
if (!accountCode) {
|
||||||
return next(new Error('no account code at setAddress stage'))
|
return next(
|
||||||
|
new Error('no account code at setAddressAndCompanyBillingInfo stage')
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let address
|
let addressAndCompanyBillingInfo
|
||||||
try {
|
try {
|
||||||
address = getAddressFromSubscriptionDetails(subscriptionDetails)
|
addressAndCompanyBillingInfo = getAddressFromSubscriptionDetails(
|
||||||
|
subscriptionDetails,
|
||||||
|
true
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(error)
|
return next(error)
|
||||||
}
|
}
|
||||||
const requestBody = RecurlyWrapper._buildXml('billing_info', address)
|
const requestBody = RecurlyWrapper._buildXml(
|
||||||
|
'billing_info',
|
||||||
|
addressAndCompanyBillingInfo
|
||||||
|
)
|
||||||
|
|
||||||
return RecurlyWrapper.apiRequest(
|
return RecurlyWrapper.apiRequest(
|
||||||
{
|
{
|
||||||
|
@ -296,7 +307,7 @@ module.exports = RecurlyWrapper = {
|
||||||
Async.apply(RecurlyWrapper._paypal.checkAccountExists, cache),
|
Async.apply(RecurlyWrapper._paypal.checkAccountExists, cache),
|
||||||
RecurlyWrapper._paypal.createAccount,
|
RecurlyWrapper._paypal.createAccount,
|
||||||
RecurlyWrapper._paypal.createBillingInfo,
|
RecurlyWrapper._paypal.createBillingInfo,
|
||||||
RecurlyWrapper._paypal.setAddress,
|
RecurlyWrapper._paypal.setAddressAndCompanyBillingInfo,
|
||||||
RecurlyWrapper._paypal.createSubscription
|
RecurlyWrapper._paypal.createSubscription
|
||||||
],
|
],
|
||||||
function(err, result) {
|
function(err, result) {
|
||||||
|
@ -1048,8 +1059,12 @@ function getCustomFieldsFromSubscriptionDetails(subscriptionDetails) {
|
||||||
return { custom_field: customFields }
|
return { custom_field: customFields }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAddressFromSubscriptionDetails(subscriptionDetails) {
|
function getAddressFromSubscriptionDetails(
|
||||||
|
subscriptionDetails,
|
||||||
|
includeCompanyInfo
|
||||||
|
) {
|
||||||
const { address } = subscriptionDetails
|
const { address } = subscriptionDetails
|
||||||
|
|
||||||
if (!address || !address.country) {
|
if (!address || !address.country) {
|
||||||
throw new Errors.InvalidError({
|
throw new Errors.InvalidError({
|
||||||
message: 'Invalid country',
|
message: 'Invalid country',
|
||||||
|
@ -1070,6 +1085,21 @@ function getAddressFromSubscriptionDetails(subscriptionDetails) {
|
||||||
country: address.country
|
country: address.country
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
includeCompanyInfo &&
|
||||||
|
subscriptionDetails.billing_info &&
|
||||||
|
subscriptionDetails.billing_info.company &&
|
||||||
|
subscriptionDetails.billing_info.company !== ''
|
||||||
|
) {
|
||||||
|
addressObject.company = subscriptionDetails.billing_info.company
|
||||||
|
if (
|
||||||
|
subscriptionDetails.billing_info.vat_number &&
|
||||||
|
subscriptionDetails.billing_info.vat_number !== ''
|
||||||
|
) {
|
||||||
|
addressObject.vat_number = subscriptionDetails.billing_info.vat_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return addressObject
|
return addressObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ div(ng-controller="RecurlySubscriptionController")
|
||||||
case personalSubscription.recurly.state
|
case personalSubscription.recurly.state
|
||||||
when "active"
|
when "active"
|
||||||
p !{translate("currently_subscribed_to_plan", {planName:"<strong>" + personalSubscription.plan.name + "</strong>"})}
|
p !{translate("currently_subscribed_to_plan", {planName:"<strong>" + personalSubscription.plan.name + "</strong>"})}
|
||||||
|
|
|
||||||
a(href, ng-click="switchToChangePlanView()", ng-if="showChangePlanButton") !{translate("change_plan")}.
|
a(href, ng-click="switchToChangePlanView()", ng-if="showChangePlanButton") !{translate("change_plan")}.
|
||||||
-if (personalSubscription.recurly.trialEndsAtFormatted && personalSubscription.recurly.trial_ends_at > Date.now())
|
-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 You're on a free trial which ends on <strong ng-non-bindable>#{personalSubscription.recurly.trialEndsAtFormatted}</strong>
|
||||||
|
|
|
@ -62,7 +62,6 @@ block content
|
||||||
novalidate
|
novalidate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
div.payment-method-toggle
|
div.payment-method-toggle
|
||||||
a.payment-method-toggle-switch(
|
a.payment-method-toggle-switch(
|
||||||
href
|
href
|
||||||
|
@ -165,22 +164,42 @@ block content
|
||||||
ng-model="data.country"
|
ng-model="data.country"
|
||||||
name="country"
|
name="country"
|
||||||
ng-change="updateCountry()"
|
ng-change="updateCountry()"
|
||||||
required,
|
|
||||||
ng-selected="{{country.code == data.country}}"
|
ng-selected="{{country.code == data.country}}"
|
||||||
|
ng-model-options="{ debounce: 200 }"
|
||||||
|
required
|
||||||
)
|
)
|
||||||
option(value='', disabled) #{translate("country")}
|
option(value='', disabled) #{translate("country")}
|
||||||
option(value='-', disabled) --------------
|
option(value='-', disabled) --------------
|
||||||
option(ng-repeat="country in countries" ng-bind-html="country.name" value="{{country.code}}")
|
option(ng-repeat="country in countries" ng-bind-html="country.name" value="{{country.code}}")
|
||||||
span.input-feedback-message {{ simpleCCForm.country.$error.required ? 'This field is required' : '' }}
|
span.input-feedback-message {{ simpleCCForm.country.$error.required ? 'This field is required' : '' }}
|
||||||
|
|
||||||
if (showVatField)
|
.form-group
|
||||||
.form-group
|
.checkbox
|
||||||
label(for="vat-no") #{translate('vat_number')}
|
label
|
||||||
input#vat-no.form-control(
|
input(
|
||||||
type="text"
|
type="checkbox"
|
||||||
ng-blur="applyVatNumber()"
|
ng-model="ui.addCompanyDetails"
|
||||||
ng-model="data.vat_number"
|
)
|
||||||
)
|
|
|
||||||
|
| #{translate("add_company_details")}
|
||||||
|
|
||||||
|
.form-group(ng-show="ui.addCompanyDetails")
|
||||||
|
label(for="company-name") #{translate("company_name")}
|
||||||
|
input#company-name.form-control(
|
||||||
|
type="text"
|
||||||
|
name="companyName"
|
||||||
|
ng-model="data.company"
|
||||||
|
)
|
||||||
|
|
||||||
|
.form-group(ng-show="ui.addCompanyDetails && price.taxes.length")
|
||||||
|
label(for="vat-number") #{translate("vat_number")}
|
||||||
|
input#vat-number.form-control(
|
||||||
|
type="text"
|
||||||
|
name="vatNumber"
|
||||||
|
ng-model="data.vat_number"
|
||||||
|
ng-blur="applyVatNumber()"
|
||||||
|
)
|
||||||
|
|
||||||
if (showCouponField)
|
if (showCouponField)
|
||||||
.form-group
|
.form-group
|
||||||
label(for="coupon-code") #{translate('coupon_code')}
|
label(for="coupon-code") #{translate('coupon_code')}
|
||||||
|
@ -192,11 +211,19 @@ block content
|
||||||
|
|
||||||
p(ng-if="paymentMethod.value === 'paypal'") #{translate("paypal_upgrade")}
|
p(ng-if="paymentMethod.value === 'paypal'") #{translate("paypal_upgrade")}
|
||||||
|
|
||||||
div.price-breakdown(ng-if="price.next.tax !== '0.00'")
|
div.price-breakdown(
|
||||||
|
ng-show="price.taxes.length"
|
||||||
|
)
|
||||||
hr.thin
|
hr.thin
|
||||||
span Total:
|
span
|
||||||
strong {{availableCurrencies[currencyCode]['symbol']}}{{price.next.total}}
|
| Total:
|
||||||
span ({{availableCurrencies[currencyCode]['symbol']}}{{price.next.subtotal}} + {{availableCurrencies[currencyCode]['symbol']}}{{price.next.tax}} tax)
|
|
|
||||||
|
strong
|
||||||
|
| {{availableCurrencies[currencyCode]['symbol']}}{{price.next.total}}
|
||||||
|
|
|
||||||
|
span
|
||||||
|
| ({{availableCurrencies[currencyCode]['symbol']}}{{price.next.subtotal}} + {{availableCurrencies[currencyCode]['symbol']}}{{price.next.tax}} tax)
|
||||||
|
|
|
||||||
span(ng-if="monthlyBilling") #{translate("every")} #{translate("month")}
|
span(ng-if="monthlyBilling") #{translate("every")} #{translate("month")}
|
||||||
span(ng-if="!monthlyBilling") #{translate("every")} #{translate("year")}
|
span(ng-if="!monthlyBilling") #{translate("every")} #{translate("year")}
|
||||||
hr.thin
|
hr.thin
|
||||||
|
|
|
@ -17,6 +17,10 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.ui = {
|
||||||
|
addCompanyDetails: false
|
||||||
|
}
|
||||||
|
|
||||||
$scope.recurlyLoadError = false
|
$scope.recurlyLoadError = false
|
||||||
$scope.currencyCode = MultiCurrencyPricing.currencyCode
|
$scope.currencyCode = MultiCurrencyPricing.currencyCode
|
||||||
$scope.allCurrencies = MultiCurrencyPricing.plans
|
$scope.allCurrencies = MultiCurrencyPricing.plans
|
||||||
|
@ -58,6 +62,8 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
address2: '',
|
address2: '',
|
||||||
state: '',
|
state: '',
|
||||||
city: '',
|
city: '',
|
||||||
|
company: '',
|
||||||
|
vat_number: '',
|
||||||
country: window.countryCode,
|
country: window.countryCode,
|
||||||
coupon: window.couponCode
|
coupon: window.couponCode
|
||||||
}
|
}
|
||||||
|
@ -99,7 +105,9 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
|
|
||||||
pricing
|
pricing
|
||||||
.plan(window.plan_code, { quantity: 1 })
|
.plan(window.plan_code, { quantity: 1 })
|
||||||
.address({ country: $scope.data.country })
|
.address({
|
||||||
|
country: $scope.data.country
|
||||||
|
})
|
||||||
.tax({ tax_code: 'digital', vat_number: '' })
|
.tax({ tax_code: 'digital', vat_number: '' })
|
||||||
.currency($scope.currencyCode)
|
.currency($scope.currencyCode)
|
||||||
.coupon($scope.data.coupon)
|
.coupon($scope.data.coupon)
|
||||||
|
@ -219,7 +227,6 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
coupon_code: pricing.items.coupon ? pricing.items.coupon.code : '',
|
coupon_code: pricing.items.coupon ? pricing.items.coupon.code : '',
|
||||||
first_name: $scope.data.first_name,
|
first_name: $scope.data.first_name,
|
||||||
last_name: $scope.data.last_name,
|
last_name: $scope.data.last_name,
|
||||||
|
|
||||||
isPaypal: $scope.paymentMethod.value === 'paypal',
|
isPaypal: $scope.paymentMethod.value === 'paypal',
|
||||||
address: {
|
address: {
|
||||||
address1: $scope.data.address1,
|
address1: $scope.data.address1,
|
||||||
|
@ -233,6 +240,21 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
postData.subscriptionDetails.isPaypal &&
|
||||||
|
$scope.ui.addCompanyDetails
|
||||||
|
) {
|
||||||
|
postData.subscriptionDetails.billing_info = {}
|
||||||
|
if ($scope.data.company && $scope.data.company !== '') {
|
||||||
|
postData.subscriptionDetails.billing_info.company =
|
||||||
|
$scope.data.company
|
||||||
|
}
|
||||||
|
if ($scope.data.vat_number && $scope.data.vat_number !== '') {
|
||||||
|
postData.subscriptionDetails.billing_info.vat_number =
|
||||||
|
$scope.data.vat_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eventTracking.sendMB('subscription-form-submitted', {
|
eventTracking.sendMB('subscription-form-submitted', {
|
||||||
currencyCode: postData.subscriptionDetails.currencyCode,
|
currencyCode: postData.subscriptionDetails.currencyCode,
|
||||||
plan_code: postData.subscriptionDetails.plan_code,
|
plan_code: postData.subscriptionDetails.plan_code,
|
||||||
|
@ -244,7 +266,6 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
'subscription-form-submitted',
|
'subscription-form-submitted',
|
||||||
postData.subscriptionDetails.plan_code
|
postData.subscriptionDetails.plan_code
|
||||||
)
|
)
|
||||||
|
|
||||||
return $http
|
return $http
|
||||||
.post('/user/subscription/create', postData)
|
.post('/user/subscription/create', postData)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
|
@ -274,9 +295,14 @@ define(['../base', '../directives/creditCards'], App =>
|
||||||
$scope.processing = true
|
$scope.processing = true
|
||||||
if ($scope.paymentMethod.value === 'paypal') {
|
if ($scope.paymentMethod.value === 'paypal') {
|
||||||
const opts = { description: $scope.planName }
|
const opts = { description: $scope.planName }
|
||||||
return recurly.paypal(opts, completeSubscription)
|
recurly.paypal(opts, completeSubscription)
|
||||||
} else {
|
} else {
|
||||||
return recurly.token($scope.data, completeSubscription)
|
const tokenData = _.cloneDeep($scope.data)
|
||||||
|
if (!$scope.ui.addCompanyDetails) {
|
||||||
|
delete tokenData.company
|
||||||
|
delete tokenData.vat_number
|
||||||
|
}
|
||||||
|
recurly.token(tokenData, completeSubscription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -862,7 +862,10 @@ describe('RecurlyWrapper', function() {
|
||||||
this.RecurlyWrapper._paypal,
|
this.RecurlyWrapper._paypal,
|
||||||
'createBillingInfo'
|
'createBillingInfo'
|
||||||
)
|
)
|
||||||
this.setAddress = sinon.stub(this.RecurlyWrapper._paypal, 'setAddress')
|
this.setAddressAndCompanyBillingInfo = sinon.stub(
|
||||||
|
this.RecurlyWrapper._paypal,
|
||||||
|
'setAddressAndCompanyBillingInfo'
|
||||||
|
)
|
||||||
this.createSubscription = sinon.stub(
|
this.createSubscription = sinon.stub(
|
||||||
this.RecurlyWrapper._paypal,
|
this.RecurlyWrapper._paypal,
|
||||||
'createSubscription'
|
'createSubscription'
|
||||||
|
@ -917,7 +920,7 @@ describe('RecurlyWrapper', function() {
|
||||||
account: { accountCode: 'xx' },
|
account: { accountCode: 'xx' },
|
||||||
billingInfo: { token_id: 'abc' }
|
billingInfo: { token_id: 'abc' }
|
||||||
})
|
})
|
||||||
this.setAddress.callsArgWith(1, null, {
|
this.setAddressAndCompanyBillingInfo.callsArgWith(1, null, {
|
||||||
user,
|
user,
|
||||||
subscriptionDetails,
|
subscriptionDetails,
|
||||||
recurlyTokenIds,
|
recurlyTokenIds,
|
||||||
|
@ -949,7 +952,7 @@ describe('RecurlyWrapper', function() {
|
||||||
this.checkAccountExists.restore()
|
this.checkAccountExists.restore()
|
||||||
this.createAccount.restore()
|
this.createAccount.restore()
|
||||||
this.createBillingInfo.restore()
|
this.createBillingInfo.restore()
|
||||||
this.setAddress.restore()
|
this.setAddressAndCompanyBillingInfo.restore()
|
||||||
return this.createSubscription.restore()
|
return this.createSubscription.restore()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -973,7 +976,7 @@ describe('RecurlyWrapper', function() {
|
||||||
this.checkAccountExists.callCount.should.equal(1)
|
this.checkAccountExists.callCount.should.equal(1)
|
||||||
this.createAccount.callCount.should.equal(1)
|
this.createAccount.callCount.should.equal(1)
|
||||||
this.createBillingInfo.callCount.should.equal(1)
|
this.createBillingInfo.callCount.should.equal(1)
|
||||||
this.setAddress.callCount.should.equal(1)
|
this.setAddressAndCompanyBillingInfo.callCount.should.equal(1)
|
||||||
this.createSubscription.callCount.should.equal(1)
|
this.createSubscription.callCount.should.equal(1)
|
||||||
return done()
|
return done()
|
||||||
})
|
})
|
||||||
|
@ -996,7 +999,7 @@ describe('RecurlyWrapper', function() {
|
||||||
this.checkAccountExists.callCount.should.equal(1)
|
this.checkAccountExists.callCount.should.equal(1)
|
||||||
this.createAccount.callCount.should.equal(1)
|
this.createAccount.callCount.should.equal(1)
|
||||||
this.createBillingInfo.callCount.should.equal(0)
|
this.createBillingInfo.callCount.should.equal(0)
|
||||||
this.setAddress.callCount.should.equal(0)
|
this.setAddressAndCompanyBillingInfo.callCount.should.equal(0)
|
||||||
this.createSubscription.callCount.should.equal(0)
|
this.createSubscription.callCount.should.equal(0)
|
||||||
return done()
|
return done()
|
||||||
})
|
})
|
||||||
|
@ -1414,12 +1417,15 @@ describe('RecurlyWrapper', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('_paypal.setAddress', function() {
|
describe('_paypal.setAddressAndCompanyBillingInfo', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.cache.account = { account_code: 'abc' }
|
this.cache.account = { account_code: 'abc' }
|
||||||
this.cache.billingInfo = {}
|
this.cache.billingInfo = {}
|
||||||
return (this.call = callback => {
|
return (this.call = callback => {
|
||||||
return this.RecurlyWrapper._paypal.setAddress(this.cache, callback)
|
return this.RecurlyWrapper._paypal.setAddressAndCompanyBillingInfo(
|
||||||
|
this.cache,
|
||||||
|
callback
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue