Skip to content

Commit 4064e5e

Browse files
committed
set RB dates to null logic
1 parent 7c67759 commit 4064e5e

File tree

4 files changed

+236
-2
lines changed

4 files changed

+236
-2
lines changed

docs/Topcoder-bookings-api.postman_collection.json

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"info": {
3-
"_postman_id": "18310e1b-429d-49db-8555-f4a54404271f",
3+
"_postman_id": "0f0620d2-acea-4e72-8d4c-6bb285d8a16a",
44
"name": "Topcoder-bookings-api",
55
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
66
},
@@ -13213,6 +13213,52 @@
1321313213
},
1321413214
"response": []
1321513215
},
13216+
{
13217+
"name": "patch resource booking set dates null",
13218+
"event": [
13219+
{
13220+
"listen": "test",
13221+
"script": {
13222+
"exec": [
13223+
"pm.test('Status code is 400', function () {\r",
13224+
" pm.response.to.have.status(400);\r",
13225+
"});"
13226+
],
13227+
"type": "text/javascript"
13228+
}
13229+
}
13230+
],
13231+
"request": {
13232+
"method": "PATCH",
13233+
"header": [
13234+
{
13235+
"key": "Authorization",
13236+
"type": "text",
13237+
"value": "Bearer {{token_bookingManager}}"
13238+
}
13239+
],
13240+
"body": {
13241+
"mode": "raw",
13242+
"raw": "{\r\n \"startDate\": null,\r\n \"endDate\": null\r\n}",
13243+
"options": {
13244+
"raw": {
13245+
"language": "json"
13246+
}
13247+
}
13248+
},
13249+
"url": {
13250+
"raw": "{{URL}}/resourceBookings/{{resourceBookingId}}",
13251+
"host": [
13252+
"{{URL}}"
13253+
],
13254+
"path": [
13255+
"resourceBookings",
13256+
"{{resourceBookingId}}"
13257+
]
13258+
}
13259+
},
13260+
"response": []
13261+
},
1321613262
{
1321713263
"name": "delete resource booking with member",
1321813264
"event": [

src/services/ResourceBookingService.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,10 @@ async function updateResourceBooking (currentUser, id, data) {
320320

321321
const resourceBooking = await ResourceBooking.findById(id)
322322
const oldValue = resourceBooking.toJSON()
323+
// We can't remove dates of Resource Booking once they are both set
324+
if (!_.isNil(oldValue.startDate) && !_.isNil(oldValue.endDate) && (_.isNull(data.startDate) || _.isNull(data.endDate))) {
325+
throw new errors.BadRequestError('You cannot remove start or end date if both are already set for Resource Booking.')
326+
}
323327
// before updating the record, we need to check if any paid work periods tried to be deleted
324328
await _ensurePaidWorkPeriodsNotDeleted(id, oldValue, data)
325329

test/unit/ResourceBookingService.test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,4 +579,59 @@ describe('resourceBooking service test', () => {
579579
expect(error.message).to.eq(data.error.message)
580580
})
581581
})
582+
describe('Update resource booking dates to null', () => {
583+
it('T36:Should not allow setting dates to null if both dates are not null', async () => {
584+
const data = testData.T36
585+
const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => {
586+
return data.resourceBooking.value
587+
})
588+
let error
589+
try {
590+
await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request)
591+
} catch (err) {
592+
error = err
593+
}
594+
expect(error.httpStatus).to.eq(data.error.httpStatus)
595+
expect(error.message).to.eq(data.error.message)
596+
expect(stubResourceBookingFindById.calledOnce).to.be.true
597+
expect(stubPostEvent.notCalled).to.be.true
598+
expect(stubCreateWorkPeriodService.callCount).to.eq(0)
599+
expect(stubUpdateWorkPeriodService.callCount).to.eq(0)
600+
expect(stubDeleteWorkPeriodService.callCount).to.eq(0)
601+
})
602+
it('T37:Should allow setting dates to null if one of the dates is null', async () => {
603+
const data = testData.T37
604+
const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => {
605+
return data.resourceBooking.value
606+
})
607+
const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => {
608+
return data.workPeriod.response
609+
})
610+
const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request)
611+
expect(entity).to.deep.eql(data.resourceBooking.response.toJSON())
612+
expect(stubResourceBookingFindById.calledOnce).to.be.true
613+
expect(stubPostEvent.calledOnce).to.be.true
614+
expect(stubWorkPeriodFindAll.called).to.be.true
615+
expect(stubCreateWorkPeriodService.callCount).to.eq(0)
616+
expect(stubUpdateWorkPeriodService.callCount).to.eq(0)
617+
expect(stubDeleteWorkPeriodService.callCount).to.eq(0)
618+
})
619+
it('T38:Should allow setting dates to null if both dates are null', async () => {
620+
const data = testData.T38
621+
const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => {
622+
return data.resourceBooking.value
623+
})
624+
const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => {
625+
return data.workPeriod.response
626+
})
627+
const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request)
628+
expect(entity).to.deep.eql(data.resourceBooking.response.toJSON())
629+
expect(stubResourceBookingFindById.calledOnce).to.be.true
630+
expect(stubPostEvent.calledOnce).to.be.true
631+
expect(stubWorkPeriodFindAll.called).to.be.true
632+
expect(stubCreateWorkPeriodService.callCount).to.eq(0)
633+
expect(stubUpdateWorkPeriodService.callCount).to.eq(0)
634+
expect(stubDeleteWorkPeriodService.callCount).to.eq(0)
635+
})
636+
})
582637
})

test/unit/common/ResourceBookingData.js

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,132 @@ const T35 = {
13511351
message: 'Can not filter or sort by some field which is not included in fields'
13521352
}
13531353
}
1354+
const T36 = {
1355+
resourceBooking: {
1356+
value: {
1357+
dataValues: {
1358+
id: '520bb632-a02a-415e-9857-93b2ecbf7d60',
1359+
projectId: 21,
1360+
userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a',
1361+
jobId: '6093e58c-683d-4022-8482-5515e8345016',
1362+
startDate: '2021-04-05',
1363+
endDate: '2021-04-17',
1364+
memberRate: 13.23,
1365+
customerRate: 13,
1366+
rateType: 'hourly',
1367+
createdAt: '2020-10-09T04:24:01.048Z',
1368+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1369+
status: 'sourcing',
1370+
billingAccountId: 68800079
1371+
}
1372+
},
1373+
request: {
1374+
startDate: '2021-04-05',
1375+
endDate: null
1376+
}
1377+
},
1378+
error: {
1379+
httpStatus: 400,
1380+
message: 'You cannot remove start or end date if both are already set for Resource Booking.'
1381+
}
1382+
}
1383+
T36.resourceBooking.value.toJSON = () => T36.resourceBooking.value.dataValues
1384+
const T37 = {
1385+
resourceBooking: {
1386+
value: {
1387+
dataValues: {
1388+
id: '520bb632-a02a-415e-9857-93b2ecbf7d60',
1389+
projectId: 21,
1390+
userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a',
1391+
jobId: '6093e58c-683d-4022-8482-5515e8345016',
1392+
startDate: null,
1393+
endDate: '2021-04-17',
1394+
memberRate: 13.23,
1395+
customerRate: 13,
1396+
rateType: 'hourly',
1397+
createdAt: '2020-10-09T04:24:01.048Z',
1398+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1399+
status: 'sourcing',
1400+
billingAccountId: 68800079
1401+
}
1402+
},
1403+
request: {
1404+
startDate: null,
1405+
endDate: null
1406+
},
1407+
response: {
1408+
dataValues: {
1409+
id: '520bb632-a02a-415e-9857-93b2ecbf7d60',
1410+
projectId: 21,
1411+
userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a',
1412+
jobId: '6093e58c-683d-4022-8482-5515e8345016',
1413+
startDate: null,
1414+
endDate: null,
1415+
memberRate: 13.23,
1416+
customerRate: 13,
1417+
rateType: 'hourly',
1418+
createdAt: '2020-10-09T04:24:01.048Z',
1419+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1420+
status: 'sourcing',
1421+
billingAccountId: 68800079
1422+
}
1423+
}
1424+
},
1425+
workPeriod: {
1426+
response: []
1427+
}
1428+
}
1429+
T37.resourceBooking.value.toJSON = () => T37.resourceBooking.value.dataValues
1430+
T37.resourceBooking.value.update = () => T37.resourceBooking.response
1431+
T37.resourceBooking.response.toJSON = () => T37.resourceBooking.response.dataValues
1432+
const T38 = {
1433+
resourceBooking: {
1434+
value: {
1435+
dataValues: {
1436+
id: '520bb632-a02a-415e-9857-93b2ecbf7d60',
1437+
projectId: 21,
1438+
userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a',
1439+
jobId: '6093e58c-683d-4022-8482-5515e8345016',
1440+
startDate: null,
1441+
endDate: null,
1442+
memberRate: 13.23,
1443+
customerRate: 13,
1444+
rateType: 'hourly',
1445+
createdAt: '2020-10-09T04:24:01.048Z',
1446+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1447+
status: 'sourcing',
1448+
billingAccountId: 68800079
1449+
}
1450+
},
1451+
request: {
1452+
startDate: null,
1453+
endDate: null
1454+
},
1455+
response: {
1456+
dataValues: {
1457+
id: '520bb632-a02a-415e-9857-93b2ecbf7d60',
1458+
projectId: 21,
1459+
userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a',
1460+
jobId: '6093e58c-683d-4022-8482-5515e8345016',
1461+
startDate: null,
1462+
endDate: null,
1463+
memberRate: 13.23,
1464+
customerRate: 13,
1465+
rateType: 'hourly',
1466+
createdAt: '2020-10-09T04:24:01.048Z',
1467+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1468+
status: 'sourcing',
1469+
billingAccountId: 68800079
1470+
}
1471+
}
1472+
},
1473+
workPeriod: {
1474+
response: []
1475+
}
1476+
}
1477+
T38.resourceBooking.value.toJSON = () => T38.resourceBooking.value.dataValues
1478+
T38.resourceBooking.value.update = () => T38.resourceBooking.response
1479+
T38.resourceBooking.response.toJSON = () => T38.resourceBooking.response.dataValues
13541480
module.exports = {
13551481
T01,
13561482
T02,
@@ -1386,5 +1512,8 @@ module.exports = {
13861512
T32,
13871513
T33,
13881514
T34,
1389-
T35
1515+
T35,
1516+
T36,
1517+
T37,
1518+
T38
13901519
}

0 commit comments

Comments
 (0)