Skip to content

Commit 854f8c3

Browse files
committed
fix: return billing account id as interger
ref issue #620
1 parent 5612ded commit 854f8c3

File tree

5 files changed

+100
-4
lines changed

5 files changed

+100
-4
lines changed

docs/permissions.html

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,43 @@ <h2 class="anchor-container">
375375
</div>
376376
</div>
377377
</div>
378+
<div class="row">
379+
<div class="col pt-5 pb-2">
380+
<h2 class="anchor-container">
381+
<a href="#section-project-billing accounts" name="section-project-billing accounts" class="anchor"></a>Project Billing Accounts
382+
</h2>
383+
</div>
384+
</div>
385+
<div class="row border-top">
386+
<div class="col py-2">
387+
<div class="permission-title anchor-container">
388+
<a href="#READ_AVL_PROJECT_BILLING_ACCOUNTS" name="READ_AVL_PROJECT_BILLING_ACCOUNTS" class="anchor"></a>Read Available Project Billing Accounts
389+
</div>
390+
<div class="permission-variable"><small><code>READ_AVL_PROJECT_BILLING_ACCOUNTS</code></small></div>
391+
<div class="text-black-50 small-text">Who can view the Billing Accounts available for the project</div>
392+
</div>
393+
<div class="col-9 py-2">
394+
<div>
395+
<span class="badge badge-primary" title="Allowed Project Role">manager</span>
396+
<span class="badge badge-primary" title="Allowed Project Role">account_manager</span>
397+
<span class="badge badge-primary" title="Allowed Project Role">program_manager</span>
398+
<span class="badge badge-primary" title="Allowed Project Role">account_executive</span>
399+
<span class="badge badge-primary" title="Allowed Project Role">solution_architect</span>
400+
<span class="badge badge-primary" title="Allowed Project Role">project_manager</span>
401+
<span class="badge badge-primary" title="Allowed Project Role">copilot</span>
402+
</div>
403+
404+
<div>
405+
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
406+
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
407+
</div>
408+
409+
<div>
410+
<span class="badge badge-dark" title="Allowed Topcoder Role">all:connect_project</span>
411+
<span class="badge badge-dark" title="Allowed Topcoder Role"></span>
412+
</div>
413+
</div>
414+
</div>
378415
<div class="row">
379416
<div class="col pt-5 pb-2">
380417
<h2 class="anchor-container">

src/routes/billingAccounts/list.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ chai.should();
1313
// demo data which might be returned by the `SalesforceService.query`
1414
const billingAccountsData = [
1515
{
16-
sfBillingAccountId: 123,
16+
sfBillingAccountId: '123',
1717
tcBillingAccountId: 123123,
1818
name: 'Billing Account 1',
1919
startDate: '2021-02-10T18:51:27Z',
2020
endDate: '2021-03-10T18:51:27Z',
2121
}, {
22-
sfBillingAccountId: 456,
22+
sfBillingAccountId: '456',
2323
tcBillingAccountId: 456456,
2424
name: 'Billing Account 2',
2525
startDate: '2011-02-10T18:51:27Z',

src/services/salesforceService.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import _ from 'lodash';
55
import config from 'config';
66
import jwt from 'jsonwebtoken';
7+
import util from '../util';
78

89
const axios = require('axios');
910

@@ -64,7 +65,11 @@ class SalesforceService {
6465
}
6566
const billingAccounts = _.get(res, 'data.records', []).map(o => ({
6667
sfBillingAccountId: _.get(o, 'Topcoder_Billing_Account__r.Id'),
67-
tcBillingAccountId: _.get(o, 'Topcoder_Billing_Account__r.TopCoder_Billing_Account_Id__c'),
68+
tcBillingAccountId: util.parseIntStrinctly(
69+
_.get(o, 'Topcoder_Billing_Account__r.TopCoder_Billing_Account_Id__c'),
70+
10,
71+
null, // fallback to null if cannot parse
72+
),
6873
name: _.get(o, 'Topcoder_Billing_Account__r.Billing_Account_Name__c'),
6974
startDate: _.get(o, 'Topcoder_Billing_Account__r.Start_Date__c'),
7075
endDate: _.get(o, 'Topcoder_Billing_Account__r.End_Date__c'),

src/util.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,34 @@ const projectServiceUtils = {
14731473
});
14741474
},
14751475

1476+
/**
1477+
* Parse integer value inside string or return fallback value.
1478+
* Unlike original parseInt, this method parses the whole string
1479+
* and fails if there are non-integer characters inside the string.
1480+
*
1481+
* @param {String} str number to parse
1482+
* @param {Number} radix radix of the number to parse
1483+
* @param {Any} fallbackValue value to return if we cannot parse successfully
1484+
*
1485+
* @returns {Number} parsed number
1486+
*/
1487+
parseIntStrictly: (str, radix, fallbackValue) => {
1488+
const int = parseInt(str, radix);
1489+
1490+
if (_.isNaN(int)) {
1491+
return fallbackValue;
1492+
}
1493+
1494+
// if we parsed only the part of value and it's not the same as intial value
1495+
// example: "12x" => 12 which is not the same as initial value "12x", which means
1496+
// we cannot parse the full value sucessfully and treat it like we cannot parse at all
1497+
if (int.toString() !== str) {
1498+
return fallbackValue;
1499+
}
1500+
1501+
return int;
1502+
},
1503+
14761504
};
14771505

14781506
_.assignIn(util, projectServiceUtils);

src/util.spec.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
11
/**
22
* Tests for util.js
33
*/
4-
import chai from 'chai';
4+
import chai, { expect } from 'chai';
55
import util from './util';
66

77
chai.should();
88

99
describe('Util method', () => {
10+
describe('parseIntStrictly', () => {
11+
it('should parse a good integer value sucessfully', () => {
12+
util.parseIntStrictly('1234567890', 10, null).should.equal(1234567890);
13+
});
14+
15+
it('should return fallback value if the initial value is a float number', () => {
16+
expect(util.parseIntStrictly('1.1', 10, null)).be.equal(null);
17+
});
18+
19+
it('should return fallback value if string can be parsed partially only', () => {
20+
expect(util.parseIntStrictly('123XXX', 10, null)).be.equal(null);
21+
});
22+
23+
it('should return fallback value if the initial value is `null`', () => {
24+
util.parseIntStrictly(null, 10, 0).should.equal(0);
25+
});
26+
27+
it('should return fallback value if the initial value is `undefined`', () => {
28+
expect(util.parseIntStrictly(undefined, 10, null)).be.equal(null);
29+
});
30+
31+
it('should return fallback value if the initial value is `""` (emtpy string)', () => {
32+
expect(util.parseIntStrictly('', 10, null)).be.equal(null);
33+
});
34+
});
35+
1036
describe('maskEmail', () => {
1137
it('should return the original value if the email is non-string', () => {
1238
chai.should().not.exist(util.maskEmail(null));

0 commit comments

Comments
 (0)