From f4c562fed21d13bf312ddf90f32ff10b2cc6bcfa Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 15 Apr 2021 01:18:50 +0300 Subject: [PATCH 1/5] Work Period Automation and Constraints --- .gitignore | 3 + config/default.js | 10 +- config/test.js | 3 +- data/demo-data.json | 2 +- ...coder-bookings-api.postman_collection.json | 1383 +++++++++++++++-- docs/swagger.yaml | 12 +- .../2021-03-30-work-period-table-create.js | 4 +- ...late-work-periods-for-resource-bookings.js | 76 + package-lock.json | 6 +- package.json | 1 + src/bootstrap.js | 1 + src/common/helper.js | 49 +- src/controllers/WorkPeriodController.js | 2 +- .../ResourceBookingEventHandler.js | 178 ++- src/eventHandlers/index.js | 3 +- src/services/ResourceBookingService.js | 112 +- src/services/WorkPeriodService.js | 3 + test/unit/JobCandidateService.test.js | 392 ----- test/unit/JobService.test.js | 415 ----- test/unit/ResourceBookingService.test.js | 537 +++---- test/unit/TeamService.test.js | 293 ---- test/unit/common/testData.js | 1208 ++++++-------- test/unit/helper.test.js | 311 ---- 23 files changed, 2327 insertions(+), 2677 deletions(-) create mode 100644 migrations/2021-04-10-populate-work-periods-for-resource-bookings.js delete mode 100644 test/unit/JobCandidateService.test.js delete mode 100644 test/unit/JobService.test.js delete mode 100644 test/unit/TeamService.test.js diff --git a/.gitignore b/.gitignore index 6ac5f84d..69ec29ae 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,9 @@ web_modules/ # Optional eslint cache .eslintcache +# Optional eslint options +.eslintrc.y*ml + # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ diff --git a/config/default.js b/config/default.js index 8088c1a8..27d25792 100644 --- a/config/default.js +++ b/config/default.js @@ -113,7 +113,7 @@ module.exports = { // the delete resource booking entity Kafka message topic TAAS_RESOURCE_BOOKING_DELETE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_DELETE_TOPIC || 'taas.resourcebooking.delete', // topics for work period service - // the create rwork period entity Kafka message topic + // the create work period entity Kafka message topic TAAS_WORK_PERIOD_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_CREATE_TOPIC || 'taas.workperiod.create', // the update work period entity Kafka message topic TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update', @@ -133,5 +133,11 @@ module.exports = { // SendGrid email template ID for requesting extension REQUEST_EXTENSION_SENDGRID_TEMPLATE_ID: process.env.REQUEST_EXTENSION_SENDGRID_TEMPLATE_ID, // the URL where TaaS App is hosted - TAAS_APP_URL: process.env.TAAS_APP_URL || 'https://platform.topcoder-dev.com/taas/myteams' + TAAS_APP_URL: process.env.TAAS_APP_URL || 'https://platform.topcoder-dev.com/taas/myteams', + // default time zone for Work Periods + WORK_PERIOD_TIME_ZONE: process.env.WORK_PERIOD_TIME_ZONE || 'America/New_York', + // maximum start date of resource bookings when populating work periods from existing resource bookings in migration script + MAX_START_DATE: process.env.MAX_START_DATE || '2100-12-31', + // maximum end date of resource bookings when populating work periods from existing resource bookings in migration script + MAX_END_DATE: process.env.MAX_END_DATE || '2100-12-31' } diff --git a/config/test.js b/config/test.js index 761b6ada..561ce3a3 100644 --- a/config/test.js +++ b/config/test.js @@ -4,5 +4,6 @@ module.exports = { AUTH0_AUDIENCE: 'http://example.com', AUTH0_AUDIENCE_UBAHN: 'http://example.com', AUTH0_CLIENT_ID: 'fake_id', - AUTH0_CLIENT_SECRET: 'fake_secret' + AUTH0_CLIENT_SECRET: 'fake_secret', + WORK_PERIOD_TIME_ZONE: 'America/New_York' } diff --git a/data/demo-data.json b/data/demo-data.json index 94bbdbb9..f2a058a3 100644 --- a/data/demo-data.json +++ b/data/demo-data.json @@ -1 +1 @@ -{"Job":[{"id":"b9887564-3d3d-4c70-8a7b-552576ef2e8d","projectId":111,"externalId":"0","description":"taas-demo-job1","title":"Demo Title","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":13,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["ee4c50c1-c8c3-475e-b6b6-edbd136a19d6","89139c80-d0a2-47c2-aa16-14589d5afd10","9f2d9127-6a2e-4506-ad76-c4ab63577b09","9515e7ee-83b6-49d1-ba5c-6c59c5a8ef1b","c854ab55-5922-4be1-8ecc-b3bc1f8629af","8456002e-fa2d-44f0-b0e7-86b1c02b6e4c","114b4ec8-805e-4c60-b351-14a955a991a9","213408aa-f16f-46c8-bc57-9e569cee3f11","b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672","23839f38-6f19-4de9-9d28-f020056bca73","289e42a3-23e9-49be-88e1-6deb93cd8c31","b403f209-63b5-42bc-9b5f-1564416640d8"],"status":"sourcing","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:36:33.409Z","updatedAt":"2021-03-30T19:11:05.033Z"},{"id":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","projectId":111,"externalId":"0","description":"taas-demo-job2","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["213408aa-f16f-46c8-bc57-9e569cee3f11","b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672","23839f38-6f19-4de9-9d28-f020056bca73","289e42a3-23e9-49be-88e1-6deb93cd8c31","b403f209-63b5-42bc-9b5f-1564416640d8"],"status":"in-review","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:36:44.975Z","updatedAt":"2021-01-28T19:38:17.463Z"},{"id":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","projectId":111,"externalId":"0","description":"taas-demo-job3","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":[],"status":"assigned","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:38:23.739Z","updatedAt":"2021-01-28T19:41:10.607Z"},{"id":"84b73f90-0fef-4507-887a-074578e5ef38","projectId":111,"externalId":"0","description":"taas-demo-job4","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["8456002e-fa2d-44f0-b0e7-86b1c02b6e4c","114b4ec8-805e-4c60-b351-14a955a991a9","213408aa-f16f-46c8-bc57-9e569cee3f11","b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672"],"status":"closed","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:41:21.892Z","updatedAt":"2021-01-28T19:41:28.849Z"},{"id":"62399aa0-b088-41fe-9e9b-0c8071f1934f","projectId":111,"externalId":"0","description":"taas-demo-job5","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672"],"status":"cancelled","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:41:35.098Z","updatedAt":"2021-01-28T19:41:42.124Z"}],"JobCandidate":[{"id":"debadcd8-64bf-4ab8-9cdb-297479eef6f5","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"4dfc6090-4ba8-4387-b5c4-584fcef982ba","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:05.723Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"7ff45b8f-2b71-4510-b760-8dfa62e79504","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"243517dd-77d7-4f70-8951-0bc66da83076","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:11.598Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"91d63d5f-01d5-419e-89df-6117ea92f535","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"a2e28bf4-1147-41a6-a39f-e2509306f2a6","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:18.066Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"257f98d9-45f7-4e13-a6c2-d7e7b6efc9fe","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"b8649393-d32f-4b7f-a156-12e9776acb0e","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:24.095Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"a01852d0-fa08-410c-b97b-67580ce62215","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"a0a3a5ce-1de6-465d-91b2-518feb299851","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:29.734Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"2fd7ca69-c8ec-4bf3-a7f3-655fbfe3e7df","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"e6958d77-ffaf-4d24-9cdb-6391506695a4","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:44.728Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"f0023058-2996-4bba-8c5f-d09a7023be38","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"626bb327-e738-48e3-8f67-1fa2dc677d3c","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:50.619Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"a189b34d-acde-4633-b18b-f7a34d7c5a74","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"b49a0adb-1565-4de1-9189-a763c77f5ed4","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:56.456Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"5191a860-4327-4c50-b76b-84beba04519b","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"79ce2a3e-7679-48cf-8ac9-0a8ca4c4b463","status":"shortlist","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:36:51.222Z","updatedAt":"2021-01-28T19:38:02.293Z"},{"id":"e6d9635c-b122-4f69-9285-09fb1ab30106","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"98ec2c16-442e-4b61-8ad1-66123ee37d3c","status":"rejected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:36:58.774Z","updatedAt":"2021-01-28T19:38:13.553Z"},{"id":"f67b155e-0f09-4fdd-89a7-d79c5e46cac6","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"05e988b7-7d54-4c10-ada1-1a04870a88a8","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:38.332Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"8ffd33d3-4a43-4719-aee4-8e46be1d8f1c","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"a2ffdeed-704d-4cf7-b70a-93fcf61de598","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:43.967Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"2b8ba549-8878-43d6-ad5f-6a66e3b9d6c9","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"4709473d-f060-4102-87f8-4d51ff0b34c1","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:50.106Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"ae5a81ec-5d05-43c4-8253-847d91a54711","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"39c7376e-2d5c-4601-bc47-6b60f505814d","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:55.734Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"85d6649e-2682-4904-9480-a77b72fef27d","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:38:30.856Z","updatedAt":"2021-01-28T19:40:27.209Z"},{"id":"922dfce3-4e06-4387-9fdb-64f70675e86b","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"dd5adacb-444d-4992-8b7b-0c349be598db","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:02.435Z","updatedAt":"2021-01-28T19:40:49.349Z"},{"id":"c26c38e2-a47d-405b-abc6-fe62a739561c","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"6d0509c7-5f12-4d84-9a19-8e80ef7ddd66","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:08.233Z","updatedAt":"2021-01-28T19:40:53.659Z"},{"id":"7bef2b37-e1ee-4638-bfc1-c911787ac955","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"f65e2104-2987-4136-839d-ee4632f0b2e5","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:13.469Z","updatedAt":"2021-01-28T19:40:57.999Z"},{"id":"e9716139-1f40-4bf1-9f8a-77ae4bcc621e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:19.215Z","updatedAt":"2021-01-28T19:41:01.953Z"},{"id":"a1731d01-eac9-4eff-8e5a-8a3c99bc66e0","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"bef43122-426b-4b2b-acdd-9b5b3bd1c0bf","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:24.625Z","updatedAt":"2021-01-28T19:41:06.370Z"}],"ResourceBooking":[{"id":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","projectId":111,"userId":"213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-01-25T19:39:28.000Z","endDate":"2021-01-31T19:39:28.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:30.052Z","updatedAt":"2021-01-28T19:40:25.260Z"},{"id":"7d967fed-9792-4768-98a7-0b644aa84f2e","projectId":111,"userId":"05e988b7-7d54-4c10-ada1-1a04870a88a8","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"in-review","startDate":"2021-01-25T19:39:34.000Z","endDate":"2021-01-31T19:39:34.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:35.571Z","updatedAt":"2021-01-28T19:40:30.291Z"},{"id":"35e1abd8-1890-4664-bb52-aade382d7b66","projectId":111,"userId":"a2ffdeed-704d-4cf7-b70a-93fcf61de598","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"closed","startDate":"2021-01-25T19:39:39.000Z","endDate":"2021-01-31T19:39:39.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:41.205Z","updatedAt":"2021-01-28T19:40:34.859Z"},{"id":"a098e8d8-ce5b-47d9-afee-38b050d16745","projectId":111,"userId":"4709473d-f060-4102-87f8-4d51ff0b34c1","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"cancelled","startDate":"2021-01-25T19:39:45.000Z","endDate":"2021-01-31T19:39:45.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:46.515Z","updatedAt":"2021-01-28T19:40:38.820Z"},{"id":"d38a6223-3f91-4300-9ecb-6e5fee173625","projectId":111,"userId":"39c7376e-2d5c-4601-bc47-6b60f505814d","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"sourcing","startDate":"2021-01-25T19:39:50.000Z","endDate":"2021-01-31T19:39:50.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:52.063Z","updatedAt":"2021-01-28T19:40:43.021Z"},{"id":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","projectId":111,"userId":"dd5adacb-444d-4992-8b7b-0c349be598db","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-01-25T19:39:58.000Z","endDate":"2021-01-31T19:39:58.000Z","memberRate":800,"customerRate":1000,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:59.432Z","updatedAt":"2021-01-28T19:40:47.743Z"},{"id":"0a6799d7-f5d1-456b-8bf1-90619284b295","projectId":111,"userId":"6d0509c7-5f12-4d84-9a19-8e80ef7ddd66","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-01-25T19:40:03.000Z","endDate":"2021-01-31T19:40:03.000Z","memberRate":2000,"customerRate":2500,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:04.761Z","updatedAt":"2021-01-28T19:40:52.303Z"},{"id":"61f5d474-e41f-490b-ab58-9f983e3d4916","projectId":111,"userId":"f65e2104-2987-4136-839d-ee4632f0b2e5","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2000-07-27T04:17:23.131Z","endDate":"2000-09-27T04:17:23.131Z","memberRate":3000,"customerRate":3500,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:09.879Z","updatedAt":"2021-01-28T19:40:56.381Z"},{"id":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","projectId":111,"userId":"e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2022-07-27T04:17:23.131Z","endDate":"2022-09-27T04:17:23.131Z","memberRate":1700,"customerRate":1900,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:15.326Z","updatedAt":"2021-01-28T19:41:00.503Z"},{"id":"8173579e-4b3c-418d-a9a1-c999caa38404","projectId":111,"userId":"bef43122-426b-4b2b-acdd-9b5b3bd1c0bf","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2020-09-27T04:17:23.131Z","endDate":"2020-09-27T04:17:23.131Z","memberRate":0,"customerRate":0,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:20.627Z","updatedAt":"2021-01-28T19:41:04.919Z"}],"WorkPeriod":[{"id":"80b85cbb-3064-45aa-bb75-9dc010848fc1","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":2,"memberRate":13.13,"customerRate":13.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:13:23.714Z","updatedAt":"2021-03-30T19:13:23.714Z"},{"id":"9b0765ef-4e20-4cb2-91f1-ce8d7bcd8062","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":2,"memberRate":13.13,"customerRate":13.13,"paymentStatus":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:14:17.109Z","updatedAt":"2021-03-30T19:14:17.109Z"},{"id":"5796eecf-cc4f-42c2-a25b-7af4710847d6","resourceBookingId":"a098e8d8-ce5b-47d9-afee-38b050d16745","userHandle":"TCConnCopilot","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":5,"memberRate":15.13,"customerRate":17.13,"paymentStatus":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:14:43.498Z","updatedAt":"2021-03-30T19:14:43.498Z"},{"id":"dba9dc5a-afaa-43b2-9b7d-f0f03af81211","resourceBookingId":"a098e8d8-ce5b-47d9-afee-38b050d16745","userHandle":"TCConnCopilot","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":5,"memberRate":15.13,"customerRate":17.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:14:56.991Z","updatedAt":"2021-03-30T19:14:56.991Z"},{"id":"d694bbea-707d-41d5-a3f4-14884ff6fbf6","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":1,"memberRate":10.13,"customerRate":18.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:15:16.106Z","updatedAt":"2021-03-30T19:15:16.106Z"},{"id":"30ff1dbe-3434-45c7-806b-0c52a41652b5","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":7,"memberRate":5.13,"customerRate":7.13,"paymentStatus":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:15:32.338Z","updatedAt":"2021-03-30T19:15:32.338Z"},{"id":"a974b73d-12a3-464e-ac97-a939f10a0726","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":7,"memberRate":5.13,"customerRate":7.13,"paymentStatus":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:15:54.822Z","updatedAt":"2021-03-30T19:15:54.822Z"},{"id":"db66b486-157b-4c0c-9a6c-03bd46c0f1d1","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":5,"memberRate":2.13,"customerRate":7.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:16:12.235Z","updatedAt":"2021-03-30T19:16:12.235Z"},{"id":"ec9195a6-cc81-4c7d-aa7b-5ac80a6926e8","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":5,"memberRate":2.13,"customerRate":7.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:16:25.772Z","updatedAt":"2021-03-30T19:16:25.772Z"},{"id":"fd59ab02-75be-4d78-bc48-2ec35af61d41","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":2,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:16:43.007Z","updatedAt":"2021-03-30T19:16:43.007Z"},{"id":"4bafda13-3319-4c46-8a31-0b9279a6e633","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":2,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:16:54.483Z","updatedAt":"2021-03-30T19:16:54.483Z"},{"id":"c4dfb0d7-1a3a-4d1a-8fa5-9fc4b555b724","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":2,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:17:07.537Z","updatedAt":"2021-03-30T19:17:07.537Z"},{"id":"0d92396b-040b-43d3-b816-7fdc9d888864","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":2,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:17:20.639Z","updatedAt":"2021-03-30T19:17:20.639Z"},{"id":"073e179b-dae7-4dd7-9cb6-a35fd1370fca","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":2,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:17:36.581Z","updatedAt":"2021-03-30T19:17:36.581Z"},{"id":"03b2d6e3-0448-4fbf-9f17-576b3dd94405","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":4,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:17:53.085Z","updatedAt":"2021-03-30T19:17:53.085Z"},{"id":"99c1dba2-a70c-4f73-b19b-9e1a66fa5fd5","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":4,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:18:10.763Z","updatedAt":"2021-03-30T19:18:10.763Z"},{"id":"854804e0-e698-424c-8cb9-cbbf885db0b6","resourceBookingId":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","userHandle":"ritesh_cs","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":4,"memberRate":2.13,"customerRate":6.13,"paymentStatus":"pending","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:18:23.704Z","updatedAt":"2021-03-30T19:18:23.704Z"},{"id":"a2242b3d-026a-493b-b186-ca16587e5701","resourceBookingId":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","userHandle":"ritesh_cs","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":6,"memberRate":12.13,"customerRate":16.13,"paymentStatus":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-03-30T19:18:36.729Z","updatedAt":"2021-03-30T19:18:36.729Z"}]} \ No newline at end of file +{"Job":[{"id":"b9887564-3d3d-4c70-8a7b-552576ef2e8d","projectId":111,"externalId":"0","description":"taas-demo-job1","title":"Demo Title","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":13,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["ee4c50c1-c8c3-475e-b6b6-edbd136a19d6","89139c80-d0a2-47c2-aa16-14589d5afd10","9f2d9127-6a2e-4506-ad76-c4ab63577b09","9515e7ee-83b6-49d1-ba5c-6c59c5a8ef1b","c854ab55-5922-4be1-8ecc-b3bc1f8629af","8456002e-fa2d-44f0-b0e7-86b1c02b6e4c","114b4ec8-805e-4c60-b351-14a955a991a9","213408aa-f16f-46c8-bc57-9e569cee3f11","b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672","23839f38-6f19-4de9-9d28-f020056bca73","289e42a3-23e9-49be-88e1-6deb93cd8c31","b403f209-63b5-42bc-9b5f-1564416640d8"],"status":"sourcing","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:36:33.409Z","updatedAt":"2021-03-30T19:11:05.033Z"},{"id":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","projectId":111,"externalId":"0","description":"taas-demo-job2","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["213408aa-f16f-46c8-bc57-9e569cee3f11","b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672","23839f38-6f19-4de9-9d28-f020056bca73","289e42a3-23e9-49be-88e1-6deb93cd8c31","b403f209-63b5-42bc-9b5f-1564416640d8"],"status":"in-review","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:36:44.975Z","updatedAt":"2021-01-28T19:38:17.463Z"},{"id":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","projectId":111,"externalId":"0","description":"taas-demo-job3","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":[],"status":"assigned","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:38:23.739Z","updatedAt":"2021-01-28T19:41:10.607Z"},{"id":"84b73f90-0fef-4507-887a-074578e5ef38","projectId":111,"externalId":"0","description":"taas-demo-job4","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["8456002e-fa2d-44f0-b0e7-86b1c02b6e4c","114b4ec8-805e-4c60-b351-14a955a991a9","213408aa-f16f-46c8-bc57-9e569cee3f11","b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672"],"status":"closed","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:41:21.892Z","updatedAt":"2021-01-28T19:41:28.849Z"},{"id":"62399aa0-b088-41fe-9e9b-0c8071f1934f","projectId":111,"externalId":"0","description":"taas-demo-job5","title":"Dummy title - at most 64 characters","startDate":"2020-09-27T04:17:23.131Z","duration":null,"numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":["b37a48db-f775-4e4e-b403-8ad1d234cdea","99b930b5-1b91-4df1-8b17-d9307107bb51","6388a632-c3ad-4525-9a73-66a527c03672"],"status":"cancelled","isApplicationPageActive":false,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:41:35.098Z","updatedAt":"2021-01-28T19:41:42.124Z"}],"JobCandidate":[{"id":"debadcd8-64bf-4ab8-9cdb-297479eef6f5","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"4dfc6090-4ba8-4387-b5c4-584fcef982ba","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:05.723Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"7ff45b8f-2b71-4510-b760-8dfa62e79504","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"243517dd-77d7-4f70-8951-0bc66da83076","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:11.598Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"91d63d5f-01d5-419e-89df-6117ea92f535","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"a2e28bf4-1147-41a6-a39f-e2509306f2a6","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:18.066Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"257f98d9-45f7-4e13-a6c2-d7e7b6efc9fe","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"b8649393-d32f-4b7f-a156-12e9776acb0e","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:24.095Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"a01852d0-fa08-410c-b97b-67580ce62215","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"a0a3a5ce-1de6-465d-91b2-518feb299851","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:29.734Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"2fd7ca69-c8ec-4bf3-a7f3-655fbfe3e7df","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"e6958d77-ffaf-4d24-9cdb-6391506695a4","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:44.728Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"f0023058-2996-4bba-8c5f-d09a7023be38","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"626bb327-e738-48e3-8f67-1fa2dc677d3c","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:50.619Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"a189b34d-acde-4633-b18b-f7a34d7c5a74","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"b49a0adb-1565-4de1-9189-a763c77f5ed4","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:37:56.456Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"5191a860-4327-4c50-b76b-84beba04519b","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"79ce2a3e-7679-48cf-8ac9-0a8ca4c4b463","status":"shortlist","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:36:51.222Z","updatedAt":"2021-01-28T19:38:02.293Z"},{"id":"e6d9635c-b122-4f69-9285-09fb1ab30106","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"98ec2c16-442e-4b61-8ad1-66123ee37d3c","status":"rejected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:36:58.774Z","updatedAt":"2021-01-28T19:38:13.553Z"},{"id":"f67b155e-0f09-4fdd-89a7-d79c5e46cac6","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"05e988b7-7d54-4c10-ada1-1a04870a88a8","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:38.332Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"8ffd33d3-4a43-4719-aee4-8e46be1d8f1c","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"a2ffdeed-704d-4cf7-b70a-93fcf61de598","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:43.967Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"2b8ba549-8878-43d6-ad5f-6a66e3b9d6c9","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"4709473d-f060-4102-87f8-4d51ff0b34c1","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:50.106Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"ae5a81ec-5d05-43c4-8253-847d91a54711","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"39c7376e-2d5c-4601-bc47-6b60f505814d","status":"open","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-01-28T19:38:55.734Z","updatedAt":"2021-03-30T19:11:05.043Z"},{"id":"85d6649e-2682-4904-9480-a77b72fef27d","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:38:30.856Z","updatedAt":"2021-01-28T19:40:27.209Z"},{"id":"922dfce3-4e06-4387-9fdb-64f70675e86b","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"dd5adacb-444d-4992-8b7b-0c349be598db","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:02.435Z","updatedAt":"2021-01-28T19:40:49.349Z"},{"id":"c26c38e2-a47d-405b-abc6-fe62a739561c","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"6d0509c7-5f12-4d84-9a19-8e80ef7ddd66","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:08.233Z","updatedAt":"2021-01-28T19:40:53.659Z"},{"id":"7bef2b37-e1ee-4638-bfc1-c911787ac955","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"f65e2104-2987-4136-839d-ee4632f0b2e5","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:13.469Z","updatedAt":"2021-01-28T19:40:57.999Z"},{"id":"e9716139-1f40-4bf1-9f8a-77ae4bcc621e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:19.215Z","updatedAt":"2021-01-28T19:41:01.953Z"},{"id":"a1731d01-eac9-4eff-8e5a-8a3c99bc66e0","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"bef43122-426b-4b2b-acdd-9b5b3bd1c0bf","status":"selected","externalId":null,"resume":null,"createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"00000000-0000-0000-0000-000000000000","createdAt":"2021-01-28T19:39:24.625Z","updatedAt":"2021-01-28T19:41:06.370Z"}],"ResourceBooking":[{"id":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","projectId":111,"userId":"213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-01-25T19:39:28.000Z","endDate":"2021-01-31T19:39:28.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:30.052Z","updatedAt":"2021-01-28T19:40:25.260Z"},{"id":"7d967fed-9792-4768-98a7-0b644aa84f2e","projectId":111,"userId":"05e988b7-7d54-4c10-ada1-1a04870a88a8","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"in-review","startDate":"2021-03-25T19:39:34.000Z","endDate":"2021-05-31T19:39:34.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:35.571Z","updatedAt":"2021-01-28T19:40:30.291Z"},{"id":"0a6799d7-f5d1-456b-8bf1-90619284b295","projectId":111,"userId":"6d0509c7-5f12-4d84-9a19-8e80ef7ddd66","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-02-27T08:40:03.000Z","endDate":"2021-03-15T09:40:03.000Z","memberRate":2000,"customerRate":2500,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:04.761Z","updatedAt":"2021-01-28T19:40:52.303Z"},{"id":"35e1abd8-1890-4664-bb52-aade382d7b66","projectId":111,"userId":"a2ffdeed-704d-4cf7-b70a-93fcf61de598","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"closed","startDate":"2021-02-25T13:39:39.000Z","endDate":"2021-04-01T05:39:39.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:41.205Z","updatedAt":"2021-01-28T19:40:34.859Z"},{"id":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","projectId":111,"userId":"dd5adacb-444d-4992-8b7b-0c349be598db","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-03-18T04:39:58.000Z","endDate":"2021-05-28T09:39:58.000Z","memberRate":800,"customerRate":1000,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:59.432Z","updatedAt":"2021-01-28T19:40:47.743Z"},{"id":"61f5d474-e41f-490b-ab58-9f983e3d4916","projectId":111,"userId":"f65e2104-2987-4136-839d-ee4632f0b2e5","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2000-03-27T11:17:23.000Z","endDate":"2000-04-27T22:17:23.000Z","memberRate":3000,"customerRate":3500,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:09.879Z","updatedAt":"2021-01-28T19:40:56.381Z"},{"id":"8173579e-4b3c-418d-a9a1-c999caa38404","projectId":111,"userId":"bef43122-426b-4b2b-acdd-9b5b3bd1c0bf","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2020-04-27T14:17:23.000Z","endDate":"2020-05-27T04:17:23.000Z","memberRate":0,"customerRate":0,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:20.627Z","updatedAt":"2021-01-28T19:41:04.919Z"},{"id":"a098e8d8-ce5b-47d9-afee-38b050d16745","projectId":111,"userId":"4709473d-f060-4102-87f8-4d51ff0b34c1","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"cancelled","startDate":"2021-04-25T20:39:45.000Z","endDate":"2021-04-30T21:39:45.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:46.515Z","updatedAt":"2021-01-28T19:40:38.820Z"},{"id":"d38a6223-3f91-4300-9ecb-6e5fee173625","projectId":111,"userId":"39c7376e-2d5c-4601-bc47-6b60f505814d","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"sourcing","startDate":"2021-05-25T16:39:50.000Z","endDate":"2021-07-31T17:39:50.000Z","memberRate":1000,"customerRate":1200,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:39:52.063Z","updatedAt":"2021-01-28T19:40:43.021Z"},{"id":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","projectId":111,"userId":"e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","status":"assigned","startDate":"2021-07-27T08:17:23.131Z","endDate":"2021-09-27T02:17:23.000Z","memberRate":1700,"customerRate":1900,"rateType":"weekly","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-01-28T19:40:15.326Z","updatedAt":"2021-01-28T19:41:00.503Z"}],"WorkPeriod":[{"id":"db3ac57b-8e78-4b68-a0f7-4e928f3059af","resourceBookingId":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","userHandle":"ritesh_cs","projectId":111,"startDate":"2021-01-24","endDate":"2021-01-30","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.105Z","updatedAt":null},{"id":"a6c83e0d-de12-42f2-b689-85ad56470941","resourceBookingId":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","userHandle":"ritesh_cs","projectId":111,"startDate":"2021-01-31","endDate":"2021-02-06","daysWorked":0,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.105Z","updatedAt":null},{"id":"5342924e-a1ed-4164-a885-7ebb87215aa5","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-04-26","endDate":"2020-05-02","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.117Z","updatedAt":null},{"id":"b8390807-8ea7-4824-9f17-4500f46f893c","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-03","endDate":"2020-05-09","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.117Z","updatedAt":null},{"id":"da056ecd-6660-4fd8-aba4-acc7ec089926","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-10","endDate":"2020-05-16","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.117Z","updatedAt":null},{"id":"2cd7a726-9909-4764-9f24-8d9a8f3d011a","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-24","endDate":"2020-05-30","daysWorked":3,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.117Z","updatedAt":null},{"id":"7f646975-f984-4967-8788-f10c8db86b25","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-05-23","endDate":"2021-05-29","daysWorked":4,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"459e0127-7f1b-41f6-9d62-d354ed537779","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-05-30","endDate":"2021-06-05","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"42f757a6-7bb3-48c2-a6cb-455d27a8821b","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-06","endDate":"2021-06-12","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"c17d9081-c442-4d55-be58-65916662653e","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-20","endDate":"2021-06-26","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"6768d502-5510-49d0-873f-346390ccf14d","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-27","endDate":"2021-07-03","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"7808d9ac-3c93-4c3f-ad35-12a0a45d51c6","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-04","endDate":"2021-07-10","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"724815e6-5a66-44c7-8dd6-7a5005ec4367","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-11","endDate":"2021-07-17","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"57210895-2e2a-46f1-a0cc-05af4c30b188","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-25","endDate":"2021-07-31","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"3534343e-5b06-4299-b657-11b3b5175dce","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":2,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"50788ef6-73d9-455c-a5ea-44028d7b3bf2","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"2b2df620-fd88-4233-a0b8-242e0bb6ecb7","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"970a2bbc-c5b7-4be5-ae63-3d9009ccf83b","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"c3b83d2b-f27b-4e4d-8f87-9f324f80a9bc","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-25","endDate":"2021-05-01","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"8dd12749-ef1d-4295-b050-8c3ecee1f846","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-09","endDate":"2021-05-15","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"db0d8eab-13b0-4fd6-98fd-d2a82cd566ad","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-02","endDate":"2021-05-08","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"278bc7a0-a242-41a4-9d00-086f5d48d5da","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-18","endDate":"2021-04-24","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"0679b699-520b-4f8b-8eb6-a6aa53ec473c","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-17","endDate":"2020-05-23","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.117Z","updatedAt":null},{"id":"c73aa1a0-cb32-4301-af96-5b33bdbda20f","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-13","endDate":"2021-06-19","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"5b0eefe1-e45d-4150-b14e-a83ce19599eb","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-18","endDate":"2021-07-24","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.120Z","updatedAt":null},{"id":"651a97b2-8019-49b7-9a8e-4c384c0615b7","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-16","endDate":"2021-05-22","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"fcdedc90-7c76-47ed-bb95-fb05ec3cd53a","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-23","endDate":"2021-05-29","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"0b65d948-0232-4f32-a455-b480da63320d","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-30","endDate":"2021-06-05","daysWorked":1,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.122Z","updatedAt":null},{"id":"1f106c81-7a0d-4fb1-9bf4-851d450709d8","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-03-26","endDate":"2000-04-01","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":null},{"id":"84a9d3e9-ee3f-495b-98de-f9fe0f6a9371","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-09","endDate":"2000-04-15","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":null},{"id":"5f9dce2b-9426-4287-b3ab-7507ff3a2671","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-16","endDate":"2000-04-22","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":null},{"id":"724b2338-c5bb-46ec-8e99-2417929eeab9","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-23","endDate":"2000-04-29","daysWorked":4,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":null},{"id":"10de7920-5e12-4284-b95f-08adc0ff1c17","resourceBookingId":"a098e8d8-ce5b-47d9-afee-38b050d16745","userHandle":"TCConnCopilot","projectId":111,"startDate":"2021-04-25","endDate":"2021-05-01","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.325Z","updatedAt":null},{"id":"c0fb6f01-7b71-471a-b85b-ea470d4dbd85","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-02-21","endDate":"2021-02-27","daysWorked":2,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":null},{"id":"0a3df77a-7841-4256-bb2c-d7e0fa17dc3f","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-02-28","endDate":"2021-03-06","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":null},{"id":"9e0d10c3-f4c8-4ba6-8c11-333d9cdab634","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":null},{"id":"66d47a95-a4f8-43a5-bfe2-af8f5a2b64ac","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":null},{"id":"c10cca56-b0c4-4e87-a64f-9a14d7445436","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"c8d38387-b4a2-49f8-bbba-2f10f50c99db","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"07dd0d62-e5cc-49a8-8b4c-966a2348095f","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"c3c4593a-2a06-4ee8-8cbb-5a3ffad8ad7d","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"9f117273-bb2f-48ab-bf3a-c13652483ea3","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-18","endDate":"2021-04-24","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"3a909050-444a-4a82-9961-d390212e86f5","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-25","endDate":"2021-05-01","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"b9a8ac04-5b06-4093-ac50-ce556d25b421","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-02","endDate":"2021-05-08","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"a2b708d1-e234-4573-b5ca-7dc36a20c0d7","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-16","endDate":"2021-05-22","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"768051e3-9765-498f-9b58-17c3377eced8","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-23","endDate":"2021-05-29","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"d94e0c2f-15de-4d07-a098-200daaa05f54","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-07-25","endDate":"2021-07-31","daysWorked":4,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"93910ea8-28ac-40a3-91b0-35eab59405da","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-01","endDate":"2021-08-07","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"33561804-7a27-4cff-9e57-c09c914bbf12","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-15","endDate":"2021-08-21","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"2e874752-81e1-451d-b5c9-7455135daee9","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-22","endDate":"2021-08-28","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"3313e61b-8733-496e-9c79-9b1e3ff5e074","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-12","endDate":"2021-09-18","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"8019e0c4-201a-469f-901b-8e84f43f577b","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-19","endDate":"2021-09-25","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"2b660631-fbd0-47fb-9ab4-f4e809650e44","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-26","endDate":"2021-10-02","daysWorked":0,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"f93b73e0-25eb-4c67-a6f0-1b658186ae29","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-02-21","endDate":"2021-02-27","daysWorked":0,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":null},{"id":"e2d7651c-b8b6-453a-b472-478fe679a22f","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-02-28","endDate":"2021-03-06","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":null},{"id":"0ed89458-ab82-485e-9727-858e7c25d477","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":1,"memberRate":null,"customerRate":null,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":null},{"id":"c1de1dd6-64b9-4dc6-b463-48c280a01465","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":null},{"id":"4b5ce032-7c8d-423a-bec3-f469cb869088","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":4,"memberRate":null,"customerRate":null,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":null},{"id":"1b5e7460-c197-4f38-8f53-80e651ee32fe","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":null},{"id":"6aae6de0-0f64-4af6-a4a4-a9920cf873fa","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":2,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"87f41144-95d3-427d-b5bf-161250a6b9e4","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-09","endDate":"2021-05-15","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":null},{"id":"06fda3ca-e583-4466-baeb-70dac8952151","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-02","endDate":"2000-04-08","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":null},{"id":"2530239e-fcd7-43a1-81ca-1df38e8744fc","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-29","endDate":"2021-09-04","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"7f58f304-800f-4304-9aa1-21c7c5aad882","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-05","endDate":"2021-09-11","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null},{"id":"08b5fc47-0e40-48d5-be46-24ecfd9031b5","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-08","endDate":"2021-08-14","daysWorked":5,"memberRate":null,"customerRate":null,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":null}]} \ No newline at end of file diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 33b2da9d..771bbdfb 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "488f8826-1016-4c2a-9d72-244c9ad4d9aa", + "_postman_id": "8ad4971b-dab3-4581-996a-9480aa21c1f4", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -2818,6 +2818,104 @@ { "name": "Resource Bookings", "item": [ + { + "name": "Before Test", + "item": [ + { + "name": "create job", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + " if(pm.response.status === \"OK\"){\r", + " const response = pm.response.json()\r", + " pm.environment.set(\"jobId\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"1212\",\n \"description\": \"Dummy Description\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 13,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"hourly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\",\n \"7d076384-ccf6-4e43-a45d-1b24b1e624aa\",\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, + { + "name": "create job with m2m", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_m2m_create_job}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"1212\",\n \"description\": \"Dummy Description\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 13,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"hourly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\",\n \"7d076384-ccf6-4e43-a45d-1b24b1e624aa\",\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + } + ] + }, { "name": "create resource booking with booking manager", "event": [ @@ -2825,8 +2923,13 @@ "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + " if(pm.response.status === \"OK\"){\r", + " const response = pm.response.json()\r", + " pm.environment.set(\"resourceBookingId\", response.id);\r", + " }\r", + "});" ], "type": "text/javascript" } @@ -2843,7 +2946,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-10-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -2862,6 +2965,96 @@ }, "response": [] }, + { + "name": "search work periods of newly created resource booking", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "url": { + "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "workPeriods" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "startDate" + }, + { + "key": "sortOrder", + "value": "asc" + }, + { + "key": "resourceBookingId", + "value": "{{resourceBookingId}}" + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{resourceBookingId}}", + "disabled": true + }, + { + "key": "paymentStatus", + "value": "pending", + "disabled": true + }, + { + "key": "startDate", + "value": "2021-03-14", + "disabled": true + }, + { + "key": "endDate", + "value": "2021-03-20", + "disabled": true + }, + { + "key": "userHandle", + "value": "pshah_manager", + "disabled": true + }, + { + "key": "projectId", + "value": "16843", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "create resource booking with m2m create", "event": [ @@ -2869,8 +3062,13 @@ "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + " if(pm.response.status === \"OK\"){\r", + " const response = pm.response.json()\r", + " pm.environment.set(\"resourceBookingIdCreatedByM2M\", response.id);\r", + " }\r", + "});" ], "type": "text/javascript" } @@ -2887,20 +3085,110 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-12-27T04:17:23.131Z\",\r\n \"endDate\": \"2021-01-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "search work periods of newly created resource booking", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "url": { + "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "workPeriods" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "startDate" + }, + { + "key": "sortOrder", + "value": "asc" + }, + { + "key": "resourceBookingId", + "value": "{{resourceBookingIdCreatedByM2M}}" + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingIdCreatedByM2M}},{{resourceBookingIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "paymentStatus", + "value": "pending", + "disabled": true + }, + { + "key": "startDate", + "value": "2021-03-14", + "disabled": true + }, + { + "key": "endDate", + "value": "2021-03-20", + "disabled": true + }, + { + "key": "userHandle", + "value": "pshah_manager", + "disabled": true + }, + { + "key": "projectId", + "value": "16843", + "disabled": true + } ] } }, @@ -2913,8 +3201,11 @@ "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" ], "type": "text/javascript" } @@ -2931,7 +3222,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -2957,7 +3248,11 @@ "listen": "test", "script": { "exec": [ - "" + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" ], "type": "text/javascript" } @@ -2974,7 +3269,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -3000,7 +3295,11 @@ "listen": "test", "script": { "exec": [ - "" + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Bad Request\")\r", + "});" ], "type": "text/javascript" } @@ -3017,7 +3316,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -3043,7 +3342,11 @@ "listen": "test", "script": { "exec": [ - "" + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Invalid Token.\")\r", + "});" ], "type": "text/javascript" } @@ -3081,6 +3384,19 @@ }, { "name": "get resource booking with booking manager", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ @@ -3105,6 +3421,19 @@ }, { "name": "get resource booking with m2m read", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ @@ -3129,6 +3458,19 @@ }, { "name": "get resource booking with booking manager from db", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ @@ -3159,6 +3501,19 @@ }, { "name": "get resource booking with connect user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ @@ -3183,6 +3538,21 @@ }, { "name": "get resource booking with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"userId: 8547899 the user is not a member of project 111\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ @@ -3206,18 +3576,192 @@ "response": [] }, { - "name": "search resource bookings with booking manager", + "name": "search resource bookings with booking manager", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "assigned", + "disabled": true + }, + { + "key": "projectIds", + "value": "111, 16705", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "search resource bookings with m2m all", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_resource_booking}}" + } + ], + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "assigned", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "search resource bookings with connect user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer {{token_connectUser}}" } ], "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/resourceBookings?sortOrder=desc", "host": [ "{{URL}}" ], @@ -3227,12 +3771,12 @@ "query": [ { "key": "page", - "value": "1", + "value": "4", "disabled": true }, { "key": "perPage", - "value": "5", + "value": "3", "disabled": true }, { @@ -3240,11 +3784,6 @@ "value": "id", "disabled": true }, - { - "key": "sortOrder", - "value": "desc", - "disabled": true - }, { "key": "startDate", "value": "2020-09-27T04:17:23.131Z", @@ -3261,14 +3800,8 @@ "disabled": true }, { - "key": "status", - "value": "sourcing", - "disabled": true - }, - { - "key": "projectIds", - "value": "111, 16705", - "disabled": true + "key": "sortOrder", + "value": "desc" } ] } @@ -3276,18 +3809,29 @@ "response": [] }, { - "name": "search resource bookings with m2m all", + "name": "search resource bookings with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_all_resource_booking}}" + "value": "Bearer {{token_member}}" } ], "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/resourceBookings?sortOrder=desc", "host": [ "{{URL}}" ], @@ -3297,12 +3841,12 @@ "query": [ { "key": "page", - "value": "1", + "value": "4", "disabled": true }, { "key": "perPage", - "value": "5", + "value": "3", "disabled": true }, { @@ -3310,11 +3854,6 @@ "value": "id", "disabled": true }, - { - "key": "sortOrder", - "value": "desc", - "disabled": true - }, { "key": "startDate", "value": "2020-09-27T04:17:23.131Z", @@ -3331,9 +3870,8 @@ "disabled": true }, { - "key": "status", - "value": "sourcing", - "disabled": true + "key": "sortOrder", + "value": "desc" } ] } @@ -3341,14 +3879,29 @@ "response": [] }, { - "name": "search resource bookings with connect user", + "name": "search resource bookings with invalid token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Invalid Token.\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer invalid_token" } ], "url": { @@ -3400,58 +3953,135 @@ "response": [] }, { - "name": "search resource bookings with member", + "name": "put resource booking with booking manager", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-26T04:17:23.131Z\",\r\n \"endDate\": \"2020-11-29T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingId}}" + ] + } + }, + "response": [] + }, + { + "name": "search extended work periods of resource booking", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_bookingManager}}" } ], "url": { - "raw": "{{URL}}/resourceBookings?sortOrder=desc", + "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "workPeriods" ], "query": [ { "key": "page", - "value": "4", + "value": "1", "disabled": true }, { "key": "perPage", - "value": "3", + "value": "5", "disabled": true }, { "key": "sortBy", - "value": "id", + "value": "startDate" + }, + { + "key": "sortOrder", + "value": "asc" + }, + { + "key": "resourceBookingId", + "value": "{{resourceBookingId}}" + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{resourceBookingId}}", + "disabled": true + }, + { + "key": "paymentStatus", + "value": "pending", "disabled": true }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2021-03-14", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2021-03-20", "disabled": true }, { - "key": "rateType", - "value": "hourly", + "key": "userHandle", + "value": "pshah_manager", "disabled": true }, { - "key": "sortOrder", - "value": "desc" + "key": "projectId", + "value": "16843", + "disabled": true } ] } @@ -3459,58 +4089,135 @@ "response": [] }, { - "name": "search resource bookings with invalid token", + "name": "put resource booking with m2m update", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-12-27T04:17:23.131Z\",\r\n \"endDate\": \"2021-01-10T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "search reduced work periods of resource booking", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_bookingManager}}" } ], "url": { - "raw": "{{URL}}/resourceBookings?sortOrder=desc", + "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "workPeriods" ], "query": [ { "key": "page", - "value": "4", + "value": "1", "disabled": true }, { "key": "perPage", - "value": "3", + "value": "5", "disabled": true }, { "key": "sortBy", - "value": "id", + "value": "startDate" + }, + { + "key": "sortOrder", + "value": "asc" + }, + { + "key": "resourceBookingId", + "value": "{{resourceBookingIdCreatedByM2M}}" + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingIdCreatedByM2M}},{{resourceBookingIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "paymentStatus", + "value": "pending", "disabled": true }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2021-03-14", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2021-03-20", "disabled": true }, { - "key": "rateType", - "value": "hourly", + "key": "userHandle", + "value": "pshah_manager", "disabled": true }, { - "key": "sortOrder", - "value": "desc" + "key": "projectId", + "value": "16843", + "disabled": true } ] } @@ -3518,19 +4225,34 @@ "response": [] }, { - "name": "put resource booking with booking manager", + "name": "put resource booking with connect user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer {{token_connectUser}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -3551,19 +4273,34 @@ "response": [] }, { - "name": "put resource booking with m2m update", + "name": "put resource booking with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_update_resource_booking}}" + "value": "Bearer {{token_member}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -3571,32 +4308,47 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ "resourceBookings", - "{{resourceBookingIdCreatedByM2M}}" + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "put resource booking with connect user", + "name": "put resource booking with user id not exist", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Bad Request\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_userId_not_exist}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -3617,19 +4369,34 @@ "response": [] }, { - "name": "put resource booking with member", + "name": "put resource booking with invalid token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Invalid Token.\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer invalid_token" } ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -3650,19 +4417,32 @@ "response": [] }, { - "name": "put resource booking with user id not exist", + "name": "patch resource booking with booking manager", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { - "method": "PUT", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-30T04:17:23.131Z\",\r\n \"endDate\": \"2020-11-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -3683,19 +4463,128 @@ "response": [] }, { - "name": "put resource booking with invalid token", + "name": "patch resource booking with m2m update", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { - "method": "PUT", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_m2m_update_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-12-30T04:17:23.131Z\",\r\n \"endDate\": \"2021-02-10T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "patch resource booking with connect user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_connectUser}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch resource booking with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -3712,23 +4601,38 @@ "{{resourceBookingId}}" ] } - }, - "response": [] - }, - { - "name": "patch resource booking with booking manager", + }, + "response": [] + }, + { + "name": "patch resource booking with user id not exist", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Bad Request\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer {{token_userId_not_exist}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-28T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", "options": { "raw": { "language": "json" @@ -3749,14 +4653,29 @@ "response": [] }, { - "name": "patch resource booking with m2m update", + "name": "patch resource booking with invalid token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Invalid Token.\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_update_resource_booking}}" + "value": "Bearer invalid_token" } ], "body": { @@ -3769,65 +4688,136 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ "resourceBookings", - "{{resourceBookingIdCreatedByM2M}}" + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "patch resource booking with connect user", + "name": "search work periods", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + " const response = pm.response.json()\r", + " pm.environment.set(\"workPeriodIdForPaid\", response[0].id);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { - "method": "PATCH", + "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_bookingManager}}" } ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "raw": "{{URL}}/workPeriods?perPage=1&sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingId}}" + "workPeriods" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "1" + }, + { + "key": "sortBy", + "value": "startDate" + }, + { + "key": "sortOrder", + "value": "asc" + }, + { + "key": "resourceBookingId", + "value": "{{resourceBookingId}}" + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{resourceBookingId}}", + "disabled": true + }, + { + "key": "paymentStatus", + "value": "pending", + "disabled": true + }, + { + "key": "startDate", + "value": "2021-03-14", + "disabled": true + }, + { + "key": "endDate", + "value": "2021-03-20", + "disabled": true + }, + { + "key": "userHandle", + "value": "pshah_manager", + "disabled": true + }, + { + "key": "projectId", + "value": "16843", + "disabled": true + } ] } }, "response": [] }, { - "name": "patch resource booking with member", + "name": "patch work period set status to completed", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"paymentStatus\": \"completed\"\r\n}", "options": { "raw": { "language": "json" @@ -3835,32 +4825,45 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "raw": "{{URL}}/workPeriods/{{workPeriodIdForPaid}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingId}}" + "workPeriods", + "{{workPeriodIdForPaid}}" ] } }, "response": [] }, { - "name": "patch resource booking with user id not exist", + "name": "patch resource booking to cancelled", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\"\r\n}", "options": { "raw": { "language": "json" @@ -3881,19 +4884,32 @@ "response": [] }, { - "name": "patch resource booking with invalid token", + "name": "patch resource booking to reduce", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "raw": "{\r\n \"startDate\": \"2020-10-04T04:17:23.131Z\"\r\n}", "options": { "raw": { "language": "json" @@ -3915,6 +4931,21 @@ }, { "name": "delete resource booking with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "DELETE", "header": [ @@ -3948,6 +4979,21 @@ }, { "name": "delete resource booking with connect user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 403', function () {\r", + " pm.response.to.have.status(403);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"You are not allowed to perform this action!\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "DELETE", "header": [ @@ -3981,6 +5027,19 @@ }, { "name": "delete resource booking with booking manager", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 400', function () {\r", + " pm.response.to.have.status(400);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "DELETE", "header": [ @@ -4014,6 +5073,19 @@ }, { "name": "delete resource booking with m2m delete", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 204', function () {\r", + " pm.response.to.have.status(204);\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "DELETE", "header": [ @@ -4047,6 +5119,21 @@ }, { "name": "delete resource booking with invalid token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + " const response = pm.response.json()\r", + " pm.expect(response.message).to.eq(\"Invalid Token.\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "DELETE", "header": [ @@ -5173,7 +6260,7 @@ }, { "key": "perPage", - "value": "5", + "value": "35", "disabled": true }, { @@ -12755,13 +13842,19 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_member}}", + "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_member}}?projectId=16718", "host": [ "{{URL}}" ], "path": [ "workPeriods", "{{workPeriodId_created_for_member}}" + ], + "query": [ + { + "key": "projectId", + "value": "16718" + } ] } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index bbd145ef..4552f8a1 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2775,7 +2775,7 @@ components: description: "The external id." status: type: string - enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] + enum: ["assigned", "closed", "cancelled"] description: "The job status." startDate: type: string @@ -2785,7 +2785,7 @@ components: endDate: type: string format: date-time - example: "2020-09-27T04:17:23.131Z" + example: "2020-09-28T04:17:23.131Z" description: "The job end date." memberRate: type: integer @@ -2838,7 +2838,7 @@ components: description: "The job id." status: type: string - enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] + enum: ["assigned", "closed", "cancelled"] description: "The job status." default: sourcing startDate: @@ -2849,7 +2849,7 @@ components: endDate: type: string format: date-time - example: "2020-09-27T04:17:23.131Z" + example: "2020-09-28T04:17:23.131Z" description: "The job end date." memberRate: type: number @@ -2869,7 +2869,7 @@ components: properties: status: type: string - enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] + enum: ["assigned", "closed", "cancelled"] startDate: type: string format: date-time @@ -2878,7 +2878,7 @@ components: endDate: type: string format: date-time - example: "2020-09-27T04:17:23.131Z" + example: "2020-09-28T04:17:23.131Z" description: "The job end date." memberRate: type: number diff --git a/migrations/2021-03-30-work-period-table-create.js b/migrations/2021-03-30-work-period-table-create.js index bf6cdb0f..04a0c66c 100644 --- a/migrations/2021-03-30-work-period-table-create.js +++ b/migrations/2021-03-30-work-period-table-create.js @@ -28,7 +28,7 @@ module.exports = { key: 'id' }, onUpdate: 'CASCADE', - onDelete: 'CASCADE', + onDelete: 'CASCADE' }, userHandle: { field: 'user_handle', @@ -89,7 +89,7 @@ module.exports = { type: Sequelize.DATE } }, { - schema: 'bookings', + schema: config.DB_SCHEMA_NAME, transaction }) await queryInterface.addIndex( diff --git a/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js b/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js new file mode 100644 index 00000000..f9947e3d --- /dev/null +++ b/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js @@ -0,0 +1,76 @@ +const config = require('config') +const ResourceBooking = require('../src/models').ResourceBooking +const _ = require('lodash') +const helper = require('../src/common/helper') +const { v4: uuid } = require('uuid') + +/* + * Populate WorkPeriods for ResourceBookings + */ + +module.exports = { + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + const Op = Sequelize.Op + try { + const resourceBookings = await ResourceBooking.findAll({ + where: { + start_date: { [Op.lt]: new Date(config.MAX_START_DATE) }, + end_date: { [Op.lt]: new Date(config.MAX_END_DATE) } + } + }) + if (resourceBookings.length === 0) { + await transaction.rollback() + return + } + const workPeriodData = [] + await Promise.all(resourceBookings.map(async rb => { + if (!_.isNil(rb.startDate) && !_.isNil(rb.endDate)) { + const periods = helper.extractWorkPeriods(rb.startDate, rb.endDate) + const user = await helper.getUserById(rb.userId) + _.forEach(periods, period => { + workPeriodData.push({ + id: uuid(), + resource_booking_id: rb.id, + project_id: rb.projectId, + user_handle: user.handle, + start_date: period.startDate, + end_date: period.endDate, + days_worked: period.daysWorked, + payment_status: 'pending', + created_by: config.m2m.M2M_AUDIT_USER_ID, + created_at: new Date() + }) + }) + } + })) + await queryInterface.bulkInsert({ tableName: 'work_periods', schema: config.DB_SCHEMA_NAME }, workPeriodData, { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + }, + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + const Op = Sequelize.Op + const resourceBookings = await ResourceBooking.findAll({ + where: { + start_date: { [Op.lt]: new Date(config.MAX_START_DATE) }, + end_date: { [Op.lt]: new Date(config.MAX_END_DATE) } + }, + // include soft-deleted resourceBookings + paranoid: false + }) + const resourceBookingIds = _.map(resourceBookings, rb => rb.dataValues.id) + + await queryInterface.bulkDelete({ tableName: 'work_periods', schema: config.DB_SCHEMA_NAME }, + { resource_booking_id: { [Op.in]: resourceBookingIds } }, { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + } +} diff --git a/package-lock.json b/package-lock.json index 225069c1..50293037 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4889,9 +4889,9 @@ "integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA==" }, "moment-timezone": { - "version": "0.5.32", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.32.tgz", - "integrity": "sha512-Z8QNyuQHQAmWucp8Knmgei8YNo28aLjJq6Ma+jy1ZSpSk5nyfRT8xgUbSQvD2+2UajISfenndwvFuH3NGS+nvA==", + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", "requires": { "moment": ">= 2.9.0" } diff --git a/package.json b/package.json index 86ab71ce..0fa27c3a 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "http-status-codes": "^2.1.4", "joi": "^17.2.1", "lodash": "^4.17.20", + "moment-timezone": "^0.5.33", "pg": "^8.4.0", "pg-hstore": "^2.3.3", "prompt-confirm": "^2.0.4", diff --git a/src/bootstrap.js b/src/bootstrap.js index a85bdec4..f3021587 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -7,6 +7,7 @@ Joi.page = () => Joi.number().integer().min(1).default(1) Joi.perPage = () => Joi.number().integer().min(1).default(20) Joi.rateType = () => Joi.string().valid('hourly', 'daily', 'weekly', 'monthly') Joi.jobStatus = () => Joi.string().valid('sourcing', 'in-review', 'assigned', 'closed', 'cancelled') +Joi.resourceBookingStatus = () => Joi.string().valid('assigned', 'closed', 'cancelled') Joi.workload = () => Joi.string().valid('full-time', 'fractional') Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview') Joi.title = () => Joi.string().max(128) diff --git a/src/common/helper.js b/src/common/helper.js index da86c854..20fdac9f 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -17,6 +17,7 @@ const logger = require('./logger') const models = require('../models') const eventDispatcher = require('./eventDispatcher') const busApi = require('@topcoder-platform/topcoder-bus-api-wrapper') +const moment = require('moment-timezone') const localLogger = { debug: (message) => logger.debug({ component: 'helper', context: message.context, message: message.message }), @@ -371,6 +372,7 @@ async function importData (pathToFile, dataModels, logger) { await indexBulkDataToES('Job', config.get('esConfig.ES_INDEX_JOB'), logger) await indexBulkDataToES('JobCandidate', config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), logger) await indexBulkDataToES('ResourceBooking', config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'), logger) + await indexBulkDataToES('WorkPeriod', config.get('esConfig.ES_INDEX_WORK_PERIOD'), logger) } /** @@ -1144,6 +1146,50 @@ async function deleteProjectMember (currentUser, projectId, projectMemberId) { } } +/** + * Populates workPeriods from start and end date of resource booking + * @param {Date} start start date of the resource booking + * @param {Date} end end date of the resource booking + * @returns {Array} information about workPeriods + */ +function extractWorkPeriods (start, end) { + // canculate daysWorked for a week + function getDaysWorked (week) { + if (weeks === 1) { + return Math.min(endDay, 5) - Math.max(startDay, 1) + 1 + } else if (week === 0) { + return Math.min(6 - startDay, 5) + } else if (week === (weeks - 1)) { + return Math.min(endDay, 5) + } else return 5 + } + const periods = [] + if (_.isNil(start) || _.isNil(end)) { + return periods + } + const startDate = moment(start) + startDate.tz(config.WORK_PERIOD_TIME_ZONE, false) + const startDay = startDate.get('day') + startDate.set('day', 0).startOf('day') + + const endDate = moment(end) + endDate.tz(config.WORK_PERIOD_TIME_ZONE, false) + const endDay = endDate.get('day') + endDate.set('day', 6).endOf('day') + + const weeks = Math.round(moment.duration(endDate - startDate).asDays()) / 7 + + for (let i = 0; i < weeks; i++) { + periods.push({ + startDate: startDate.format('YYYY-MM-DD'), + endDate: startDate.add(6, 'day').format('YYYY-MM-DD'), + daysWorked: getDaysWorked(i) + }) + startDate.add(1, 'day') + } + return periods +} + module.exports = { getParamFromCliArgs, promptUser, @@ -1186,5 +1232,6 @@ module.exports = { createProjectMember, listProjectMembers, listProjectMemberInvites, - deleteProjectMember + deleteProjectMember, + extractWorkPeriods } diff --git a/src/controllers/WorkPeriodController.js b/src/controllers/WorkPeriodController.js index 6d36e874..8a54defa 100644 --- a/src/controllers/WorkPeriodController.js +++ b/src/controllers/WorkPeriodController.js @@ -1,5 +1,5 @@ /** - * Controller for ResourceBooking endpoints + * Controller for WorkPeriod endpoints */ const HttpStatus = require('http-status-codes') const service = require('../services/WorkPeriodService') diff --git a/src/eventHandlers/ResourceBookingEventHandler.js b/src/eventHandlers/ResourceBookingEventHandler.js index 69dbe1dd..3fc483fa 100644 --- a/src/eventHandlers/ResourceBookingEventHandler.js +++ b/src/eventHandlers/ResourceBookingEventHandler.js @@ -9,6 +9,8 @@ const logger = require('../common/logger') const helper = require('../common/helper') const JobService = require('../services/JobService') const JobCandidateService = require('../services/JobCandidateService') +const WorkPeriodService = require('../services/WorkPeriodService') +const WorkPeriod = models.WorkPeriod /** * When ResourceBooking's status is changed to `assigned` @@ -124,6 +126,167 @@ async function assignJob (payload) { } } +/** + * When a ResourceBooking is created, workPeriods that cover each weeks + * of resource booking should be also created + * @param {object} payload the event payload + * @returns {undefined} + */ +async function createWorkPeriods (payload) { + // if startDate or endDate is not provided then we can't create work period + if (_.isNil(payload.value.startDate) || _.isNil(payload.value.endDate)) { + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'createWorkPeriods', + message: `id: ${payload.value.id} resource booking without endDate or startDate - ignored` + }) + return + } + // collect dates of work periods + const workPeriodDates = helper.extractWorkPeriods(payload.value.startDate, payload.value.endDate) + await _createWorkPeriods(workPeriodDates, payload.value.id) + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'createWorkPeriods', + message: `WorkPeriods created for resource booking with id: ${payload.value.id}` + }) +} + +/** + * When a ResourceBooking is updated, workPeriods related to + * that ResourceBooking should be updated also. + * This function finds aout which workPeriods should be deleted, + * which ones should be created and which ones should be updated + * @param {object} payload the event payload + * @returns {undefined} + */ +async function updateWorkPeriods (payload) { + // find related workPeriods to evaluate the changes + const workPeriods = await WorkPeriod.findAll({ + where: { + resourceBookingId: payload.value.id + }, + raw: true + }) + // gather workPeriod dates + const newWorkPeriods = helper.extractWorkPeriods(payload.value.startDate || payload.options.oldValue.startDate, payload.value.endDate || payload.options.oldValue.endDate) + // find which workPeriods should be removed + const workPeriodsToRemove = _.differenceBy(workPeriods, newWorkPeriods, 'startDate') + // find which workperiods should be created + const workPeriodsToAdd = _.differenceBy(newWorkPeriods, workPeriods, 'startDate') + // find which workperiods' daysWorked propery should be updated + let workPeriodsToUpdate = _.intersectionBy(newWorkPeriods, workPeriods, 'startDate') + workPeriodsToUpdate = _.differenceWith(workPeriodsToUpdate, workPeriods, (a, b) => b.startDate === a.startDate && b.daysWorked === a.daysWorked) + // include id + workPeriodsToUpdate = _.map(workPeriodsToUpdate, wpu => { + wpu.id = _.filter(workPeriods, ['startDate', wpu.startDate])[0].id + return wpu + }) + if (workPeriodsToRemove.length === 0 && workPeriodsToAdd.length === 0 && workPeriodsToUpdate.length === 0) { + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'updateWorkPeriods', + message: `id: ${payload.value.id} resource booking has no change in dates - ignored` + }) + return + } + if (workPeriodsToRemove.length > 0) { + await _deleteWorkPeriods(workPeriodsToRemove) + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'updateWorkPeriods', + message: `Old WorkPeriods deleted for resource booking with id: ${payload.value.id}` + }) + } + if (workPeriodsToAdd.length > 0) { + await _createWorkPeriods(workPeriodsToAdd, payload.value.id) + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'updateWorkPeriods', + message: `New WorkPeriods created for resource booking with id: ${payload.value.id}` + }) + } + if (workPeriodsToUpdate.length > 0) { + await _updateWorkPeriods(workPeriodsToUpdate) + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'updateWorkPeriods', + message: `WorkPeriods updated for resource booking with id: ${payload.value.id}` + }) + } +} + +/** + * When a ResourceBooking is deleted, workPeriods related to + * that ResourceBooking should also be deleted + * @param {object} payload the event payload + * @returns {undefined} + */ +async function deleteWorkPeriods (payload) { + // find related workPeriods to delete + const workPeriods = await WorkPeriod.findAll({ + where: { + resourceBookingId: payload.value.id + }, + raw: true + }) + if (workPeriods.length === 0) { + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'deleteWorkPeriods', + message: `id: ${payload.value.id} resource booking has no workPeriods - ignored` + }) + return + } + await _deleteWorkPeriods(workPeriods) + logger.debug({ + component: 'ResourceBookingEventHandler', + context: 'deleteWorkPeriods', + message: `WorkPeriods deleted for resource booking with id: ${payload.value.id}` + }) +} + +/** + * Calls WorkPeriodService to create workPeriods + * @param {Array<{startDate:Date, + * endDate:Date, daysWorked:number}>} periods work period data + * @param {string} resourceBookingId resourceBookingId of work period + * @returns {undefined} + */ +async function _createWorkPeriods (periods, resourceBookingId) { + Promise.all(_.forEach(periods, async period => await WorkPeriodService.createWorkPeriod(helper.getAuditM2Muser(), + { + resourceBookingId: resourceBookingId, + startDate: period.startDate, + endDate: period.endDate, + daysWorked: period.daysWorked, + paymentStatus: 'pending' + }))) +} + +/** + * Calls WorkPeriodService to update workPeriods + * @param {Array<{daysWorked:number}>} periods work period data + * @returns {undefined} + */ +async function _updateWorkPeriods (periods) { + Promise.all(_.forEach(periods, async period => await WorkPeriodService.partiallyUpdateWorkPeriod(helper.getAuditM2Muser(), + period.id, + { + daysWorked: period.daysWorked + }))) +} + +/** + * Calls WorkPeriodService to delete workPeriods + * @param {Array<{id:string}>} workPeriods work period objects + * @returns {undefined} + */ +async function _deleteWorkPeriods (workPeriods) { + Promise.all(_.forEach(workPeriods, + async workPeriod => await WorkPeriodService.deleteWorkPeriod(helper.getAuditM2Muser(), workPeriod.id))) +} + /** * Process resource booking create event. * @@ -133,6 +296,7 @@ async function assignJob (payload) { async function processCreate (payload) { await selectJobCandidate(payload) await assignJob(payload) + await createWorkPeriods(payload) } /** @@ -144,9 +308,21 @@ async function processCreate (payload) { async function processUpdate (payload) { await selectJobCandidate(payload) await assignJob(payload) + await updateWorkPeriods(payload) +} + +/** + * Process resource booking delete event. + * + * @param {Object} payload the event payload + * @returns {undefined} + */ +async function processDelete (payload) { + await deleteWorkPeriods(payload) } module.exports = { processCreate, - processUpdate + processUpdate, + processDelete } diff --git a/src/eventHandlers/index.js b/src/eventHandlers/index.js index f4089ea0..309b5f82 100644 --- a/src/eventHandlers/index.js +++ b/src/eventHandlers/index.js @@ -13,7 +13,8 @@ const TopicOperationMapping = { [config.TAAS_JOB_UPDATE_TOPIC]: JobEventHandler.processUpdate, [config.TAAS_JOB_CANDIDATE_CREATE_TOPIC]: JobCandidateEventHandler.processCreate, [config.TAAS_RESOURCE_BOOKING_CREATE_TOPIC]: ResourceBookingEventHandler.processCreate, - [config.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC]: ResourceBookingEventHandler.processUpdate + [config.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC]: ResourceBookingEventHandler.processUpdate, + [config.TAAS_RESOURCE_BOOKING_DELETE_TOPIC]: ResourceBookingEventHandler.processDelete } /** diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index 120b9539..bde6101a 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -14,6 +14,7 @@ const errors = require('../common/errors') const models = require('../models') const ResourceBooking = models.ResourceBooking +const WorkPeriod = models.WorkPeriod const esClient = helper.getESClient() /** @@ -42,6 +43,50 @@ async function _checkUserPermissionForGetResourceBooking (currentUser, projectId } } +/** + * Check if any work period is paid and tried to be deleted + * + * @param {string} resourceBookingId workPeriod object array. + * @param {Object} [oldValue] old value of resourceBooking object. + * @param {Object} [newValue] new value of resourceBooking object. + * @throws {BadRequestError} + */ +async function _ensurePaidWorkPeriodsNotDeleted (resourceBookingId, oldValue, newValue) { + function _checkForPaidWorkPeriods (workPeriods) { + const paidWorkPeriods = _.filter(workPeriods + , workPeriod => _.includes(['completed', 'partially-completed'], workPeriod.paymentStatus)) + if (paidWorkPeriods.length > 0) { + throw new errors.BadRequestError(`WorkPeriods with id of ${_.map(paidWorkPeriods, workPeriod => workPeriod.id)} + has completed or partially-completed payment status.`) + } + } + // find related workPeriods to evaluate the changes + const workPeriods = await WorkPeriod.findAll({ + where: { + resourceBookingId: resourceBookingId + }, + raw: true + }) + // oldValue and newValue are not provided at deleteResourceBooking process + if (_.isUndefined(oldValue) || _.isUndefined(newValue)) { + _checkForPaidWorkPeriods(workPeriods) + return + } + // We should not be able to change status of ResourceBooking to 'cancelled' + // if there is at least one associated Work Period with paymentStatus 'partially-completed' or 'completed'. + if (oldValue.status !== 'cancelled' && newValue.status === 'cancelled') { + _checkForPaidWorkPeriods(workPeriods) + // we have already checked all existing workPeriods + return + } + // gather workPeriod dates from provided dates + const newWorkPeriods = helper.extractWorkPeriods(newValue.startDate || oldValue.startDate, newValue.endDate || oldValue.endDate) + // find which workPeriods should be removed + const workPeriodsToRemove = _.differenceBy(workPeriods, newWorkPeriods, 'startDate') + // we can't delete workperiods with paymentStatus 'partially-completed' or 'completed'. + _checkForPaidWorkPeriods(workPeriodsToRemove) +} + /** * Get resourceBooking by id * @param {Object} currentUser the user who perform this operation. @@ -113,12 +158,19 @@ async function createResourceBooking (currentUser, resourceBooking) { createResourceBooking.schema = Joi.object().keys({ currentUser: Joi.object().required(), resourceBooking: Joi.object().keys({ - status: Joi.jobStatus().default('sourcing'), + status: Joi.resourceBookingStatus().default('assigned'), projectId: Joi.number().integer().required(), userId: Joi.string().uuid().required(), jobId: Joi.string().uuid().allow(null), startDate: Joi.date().allow(null), - endDate: Joi.date().allow(null), + endDate: Joi.date().when('startDate', { + is: Joi.exist(), + then: Joi.date().allow(null).greater(Joi.ref('startDate') + ).messages({ + 'date.greater': 'endDate must be greater than startDate' + }), + otherwise: Joi.date().allow(null) + }), memberRate: Joi.number().allow(null), customerRate: Joi.number().allow(null), rateType: Joi.rateType().required() @@ -127,9 +179,9 @@ createResourceBooking.schema = Joi.object().keys({ /** * Update resourceBooking - * @params {Object} currentUser the user who perform this operation - * @params {String} id the resourceBooking id - * @params {Object} data the data to be updated + * @param {Object} currentUser the user who perform this operation + * @param {String} id the resourceBooking id + * @param {Object} data the data to be updated * @returns {Object} the updated resourceBooking */ async function updateResourceBooking (currentUser, id, data) { @@ -140,6 +192,8 @@ async function updateResourceBooking (currentUser, id, data) { const resourceBooking = await ResourceBooking.findById(id) const oldValue = resourceBooking.toJSON() + // before updating the record, we need to check if any paid work periods tried to be deleted + await _ensurePaidWorkPeriodsNotDeleted(id, oldValue, data) data.updatedBy = await helper.getUserId(currentUser.userId) @@ -151,9 +205,9 @@ async function updateResourceBooking (currentUser, id, data) { /** * Partially update resourceBooking by id - * @params {Object} currentUser the user who perform this operation - * @params {String} id the resourceBooking id - * @params {Object} data the data to be updated + * @param {Object} currentUser the user who perform this operation + * @param {String} id the resourceBooking id + * @param {Object} data the data to be updated * @returns {Object} the updated resourceBooking */ async function partiallyUpdateResourceBooking (currentUser, id, data) { @@ -164,9 +218,16 @@ partiallyUpdateResourceBooking.schema = Joi.object().keys({ currentUser: Joi.object().required(), id: Joi.string().uuid().required(), data: Joi.object().keys({ - status: Joi.jobStatus(), + status: Joi.resourceBookingStatus(), startDate: Joi.date().allow(null), - endDate: Joi.date().allow(null), + endDate: Joi.date().when('startDate', { + is: Joi.exist(), + then: Joi.date().allow(null).greater(Joi.ref('startDate') + ).messages({ + 'date.greater': 'endDate must be greater than startDate' + }), + otherwise: Joi.date().allow(null) + }), memberRate: Joi.number().allow(null), customerRate: Joi.number().allow(null), rateType: Joi.rateType() @@ -175,9 +236,9 @@ partiallyUpdateResourceBooking.schema = Joi.object().keys({ /** * Fully update resourceBooking by id - * @params {Object} currentUser the user who perform this operation - * @params {String} id the resourceBooking id - * @params {Object} data the data to be updated + * @param {Object} currentUser the user who perform this operation + * @param {String} id the resourceBooking id + * @param {Object} data the data to be updated * @returns {Object} the updated resourceBooking */ async function fullyUpdateResourceBooking (currentUser, id, data) { @@ -196,18 +257,25 @@ fullyUpdateResourceBooking.schema = Joi.object().keys({ userId: Joi.string().uuid().required(), jobId: Joi.string().uuid().allow(null).default(null), startDate: Joi.date().allow(null).default(null), - endDate: Joi.date().allow(null).default(null), + endDate: Joi.date().when('startDate', { + is: Joi.exist(), + then: Joi.date().allow(null).default(null).greater(Joi.ref('startDate') + ).messages({ + 'date.greater': 'endDate must be greater than startDate' + }), + otherwise: Joi.date().allow(null).default(null) + }), memberRate: Joi.number().allow(null).default(null), customerRate: Joi.number().allow(null).default(null), rateType: Joi.rateType().required(), - status: Joi.jobStatus().default('sourcing') + status: Joi.resourceBookingStatus().required() }).required() }).required() /** * Delete resourceBooking by id - * @params {Object} currentUser the user who perform this operation - * @params {String} id the resourceBooking id + * @param {Object} currentUser the user who perform this operation + * @param {String} id the resourceBooking id */ async function deleteResourceBooking (currentUser, id) { // check permission @@ -215,6 +283,8 @@ async function deleteResourceBooking (currentUser, id) { throw new errors.ForbiddenError('You are not allowed to perform this action!') } + // we can't delete workperiods with paymentStatus 'partially-completed' or 'completed'. + await _ensurePaidWorkPeriodsNotDeleted(id) const resourceBooking = await ResourceBooking.findById(id) await resourceBooking.destroy() await helper.postEvent(config.TAAS_RESOURCE_BOOKING_DELETE_TOPIC, { id }) @@ -228,8 +298,8 @@ deleteResourceBooking.schema = Joi.object().keys({ /** * List resourceBookings * @param {Object} currentUser the user who perform this operation. - * @params {Object} criteria the search criteria - * @params {Object} options the extra options to control the function + * @param {Object} criteria the search criteria + * @param {Object} options the extra options to control the function * @returns {Object} the search result, contain total/page/perPage and result array */ async function searchResourceBookings (currentUser, criteria, options = { returnAll: false }) { @@ -323,7 +393,7 @@ async function searchResourceBookings (currentUser, criteria, options = { return logger.logFullError(err, { component: 'ResourceBookingService', context: 'searchResourceBookings' }) } logger.info({ component: 'ResourceBookingService', context: 'searchResourceBookings', message: 'fallback to DB query' }) - const filter = {} + const filter = { [Op.and]: [] } _.each(_.pick(criteria, ['status', 'startDate', 'endDate', 'rateType', 'projectId', 'jobId', 'userId']), (value, key) => { filter[Op.and].push({ [key]: value }) }) @@ -352,7 +422,7 @@ searchResourceBookings.schema = Joi.object().keys({ perPage: Joi.number().integer(), sortBy: Joi.string().valid('id', 'rateType', 'startDate', 'endDate', 'customerRate', 'memberRate', 'status'), sortOrder: Joi.string().valid('desc', 'asc'), - status: Joi.jobStatus(), + status: Joi.resourceBookingStatus(), startDate: Joi.date(), endDate: Joi.date(), rateType: Joi.rateType(), diff --git a/src/services/WorkPeriodService.js b/src/services/WorkPeriodService.js index 4f143979..55903c3c 100644 --- a/src/services/WorkPeriodService.js +++ b/src/services/WorkPeriodService.js @@ -320,6 +320,9 @@ async function deleteWorkPeriod (currentUser, id) { } const workPeriod = await WorkPeriod.findById(id) + if (_.includes(['completed', 'partially-completed'], workPeriod.paymentStatus)) { + throw new errors.BadRequestError("Can't delete WorkPeriod with paymentStatus completed or partially-completed") + } await workPeriod.destroy() await helper.postEvent(config.TAAS_WORK_PERIOD_DELETE_TOPIC, { id }) } diff --git a/test/unit/JobCandidateService.test.js b/test/unit/JobCandidateService.test.js deleted file mode 100644 index bfa7b9c2..00000000 --- a/test/unit/JobCandidateService.test.js +++ /dev/null @@ -1,392 +0,0 @@ -/* eslint-disable no-unused-expressions */ -process.env.NODE_ENV = 'test' -require('../../src/bootstrap') - -const expect = require('chai').expect -const sinon = require('sinon') -const _ = require('lodash') -const models = require('../../src/models') -const service = require('../../src/services/JobCandidateService') -const { - bookingManagerUser, connectUser, topCoderUser, jobCandidateRequestBody, - jobResponseBody, jobCandidateResponseBody, fullyUpdateJobCandidateRequestBody, partiallyUpdateJobCandidateRequestBody, unexpected -} = require('./common/testData') - -const helper = require('../../src/common/helper') -const esClient = helper.getESClient() -const busApiClient = helper.getBusApiClient() - -const JobCandidate = models.JobCandidate -const Job = models.Job - -describe('jobCandidate service test', () => { - let isConnectMember - let userId - let stubIsConnectMember - let stubGetUserId - let stubPostEvent - beforeEach(() => { - isConnectMember = true - stubIsConnectMember = sinon.stub(helper, 'isConnectMember').callsFake(() => { - return isConnectMember - }) - - userId = 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a' - stubGetUserId = sinon.stub(helper, 'getUserId').callsFake(() => { - return userId - }) - stubPostEvent = sinon.stub(busApiClient, 'postEvent').callsFake(async () => {}) - }) - - afterEach(() => { - sinon.restore() - }) - - describe('create job candidate test', () => { - it('create job candidate with booking manager success ', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubDBCreate = sinon.stub(JobCandidate, 'create').callsFake(() => { - return jobCandidateResponseBody - }) - - const entity = await service.createJobCandidate(bookingManagerUser, jobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubDBCreate.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('create job candidate with connect user success ', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubDBCreate = sinon.stub(JobCandidate, 'create').callsFake(() => { - return jobCandidateRes - }) - const entity = await service.createJobCandidate(connectUser, jobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubDBCreate.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('create job candidate with topcoder user success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubDBCreate = sinon.stub(JobCandidate, 'create').callsFake(() => { - return jobCandidateRes - }) - const entity = await service.createJobCandidate(topCoderUser, jobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubDBCreate.calledOnce).to.be.true - expect(stubDBCreate.calledOnce).to.be.true - }) - }) - - describe('get job candidate test', () => { - it('get job candidate success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - return { - body: { - _id: jobCandidateRes.dataValues.id, - _source: _.omit(jobCandidateRes.dataValues, ['id']) - } - } - }) - const entity = await service.getJobCandidate(jobCandidateResponseBody.dataValues.id) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('get job candidate with candidate not exist success', async () => { - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - const err = new Error() - err.statusCode = 404 - throw err - }) - try { - await service.getJobCandidate(jobCandidateResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal(`id: ${jobCandidateResponseBody.dataValues.id} "JobCandidate" not found`) - expect(stub.calledOnce).to.be.true - } - }) - - it('get job candidate from db success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return jobCandidateRes - }) - const entity = await service.getJobCandidate(jobCandidateResponseBody.dataValues.id, true) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - }) - - it('get job candidate from db with candidate not exist success', async () => { - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return null - }) - try { - await service.getJobCandidate(jobCandidateResponseBody.dataValues.id, true) - unexpected() - } catch (error) { - expect(error.message).to.equal(`id: ${jobCandidateResponseBody.dataValues.id} "JobCandidate" doesn't exists.`) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - } - }) - }) - - describe('fully update job candidate test', () => { - it('fully update job candidate test with booking manager success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - const entity = await service.fullyUpdateJobCandidate(bookingManagerUser, jobCandidateResponseBody.dataValues.id, fullyUpdateJobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - - it('fully update job candidate test with connect user success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - - const entity = await service.fullyUpdateJobCandidate(connectUser, jobCandidateResponseBody.dataValues.id, fullyUpdateJobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - }) - - it('fully update job candidate test with topcoder user success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - const user = _.assign({}, topCoderUser, { userId: 40152856 }) - - const entity = await service.fullyUpdateJobCandidate(user, jobCandidateResponseBody.dataValues.id, fullyUpdateJobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - - it('fully update job candidate test with topcoder user failed', async () => { - userId = '544e281f-62a0-4e45-8cc1-bac434bb3a54' - isConnectMember = false - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - try { - await service.fullyUpdateJobCandidate(topCoderUser, jobCandidateResponseBody.dataValues.id, fullyUpdateJobCandidateRequestBody) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - }) - }) - - describe('partially update job candidate test', () => { - it('partially update job candidate test with booking manager success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - - const entity = await service.partiallyUpdateJobCandidate(bookingManagerUser, jobCandidateResponseBody.dataValues.id, partiallyUpdateJobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - - it('partially update job candidate test with connect user success', async () => { - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - - const entity = await service.partiallyUpdateJobCandidate(connectUser, jobCandidateResponseBody.dataValues.id, partiallyUpdateJobCandidateRequestBody) - expect(entity).to.deep.eql(jobCandidateRes.dataValues) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - }) - - it('partially update job candidate test with topcoder user failed', async () => { - isConnectMember = false - userId = '544e281f-62a0-4e45-8cc1-bac434bb3a54' - const jobCandidateRes = _.cloneDeep(jobCandidateResponseBody) - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ...jobCandidateRes, - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - try { - await service.partiallyUpdateJobCandidate(topCoderUser, jobCandidateResponseBody.dataValues.id, partiallyUpdateJobCandidateRequestBody) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - }) - - it('partially update job candidate test with job not exist', async () => { - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ..._.cloneDeep(jobCandidateResponseBody), - update: () => { return null } - } - }) - const stubJobFindOne = sinon.stub(Job, 'findOne').callsFake(() => { - return null - }) - - await service.partiallyUpdateJobCandidate(bookingManagerUser, jobCandidateResponseBody.dataValues.id, partiallyUpdateJobCandidateRequestBody) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubJobFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - }) - - describe('delete job candidate test', () => { - it('delete job candidate test with booking manager success', async () => { - const stubJobCandidateFindOne = sinon.stub(JobCandidate, 'findOne').callsFake(() => { - return { - ..._.cloneDeep(jobCandidateResponseBody), - update: () => { return null } - } - }) - await service.deleteJobCandidate(bookingManagerUser, jobCandidateResponseBody.dataValues.id) - expect(stubJobCandidateFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - - it('delete job candidate test with connect user success', async () => { - try { - await service.deleteJobCandidate(connectUser, jobCandidateResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - - it('delete job candidate test with topcoder user failed', async () => { - try { - await service.deleteJobCandidate(topCoderUser, jobCandidateResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - }) - - describe('search job candidates test', () => { - it('search job candidates success', async () => { - const stub = sinon.stub(esClient, 'search').callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: jobCandidateResponseBody.dataValues.id, - _source: _.omit(jobCandidateResponseBody.dataValues, ['id']) - }] - } - } - } - }) - const entity = await service.searchJobCandidates({ sortBy: 'id', sortOrder: 'asc', page: 1, perPage: 1, jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed' }) - expect(entity.result[0]).to.deep.eql(jobCandidateResponseBody.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('search job candidates without query parameters success', async () => { - const stub = sinon.stub(esClient, 'search').callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: jobCandidateResponseBody.dataValues.id, - _source: _.omit(jobCandidateResponseBody.dataValues, ['id']) - }] - } - } - } - }) - const entity = await service.searchJobCandidates({}) - expect(entity.result[0]).to.deep.eql(jobCandidateResponseBody.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('search job candidates success when es search fails', async () => { - const stubESSearch = sinon.stub(esClient, 'search').callsFake(() => { - throw new Error('dedicated es failure') - }) - - const stubDBSearch = sinon.stub(JobCandidate, 'findAll').callsFake(() => { - return [jobCandidateResponseBody] - }) - const entity = await service.searchJobCandidates({ sortBy: 'id', sortOrder: 'asc', page: 1, perPage: 1, jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed' }) - expect(entity.result[0]).to.deep.eql(jobCandidateResponseBody.dataValues) - expect(stubESSearch.calledOnce).to.be.true - expect(stubDBSearch.calledOnce).to.be.true - }) - }) -}) diff --git a/test/unit/JobService.test.js b/test/unit/JobService.test.js deleted file mode 100644 index 0f0d7ef2..00000000 --- a/test/unit/JobService.test.js +++ /dev/null @@ -1,415 +0,0 @@ -/* eslint-disable no-unused-expressions */ -process.env.NODE_ENV = 'test' -const _ = require('lodash') -require('../../src/bootstrap') - -const expect = require('chai').expect -const sinon = require('sinon') -const models = require('../../src/models') -const service = require('../../src/services/JobService') -const { - bookingManagerUser, connectUser, topCoderUser, jobRequestBody, - jobResponseBody, fullyUpdateJobRequestBody, partiallyUpdateJobRequestBody, unexpected -} = require('./common/testData') -const helper = require('../../src/common/helper') -const errors = require('../../src/common/errors') - -const esClient = helper.getESClient() -const busApiClient = helper.getBusApiClient() - -const Job = models.Job - -describe('job service test', () => { - let isConnectMember - let userId - let stubIsConnectMember - let stubGetUserId - let stubPostEvent - beforeEach(() => { - isConnectMember = true - stubIsConnectMember = sinon.stub(helper, 'isConnectMember').callsFake(() => { - return isConnectMember - }) - - userId = 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a' - stubGetUserId = sinon.stub(helper, 'getUserId').callsFake(() => { - return userId - }) - stubPostEvent = sinon.stub(busApiClient, 'postEvent').callsFake(async () => {}) - }) - - afterEach(() => { - sinon.restore() - }) - - describe('create job test', () => { - it('create job with booking manager user success ', async () => { - const stubDBCreate = sinon.stub(Job, 'create').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - - const entity = await service.createJob(bookingManagerUser, jobRequestBody) - expect(entity).to.deep.eql(jobResponseBody.dataValues) - expect(stubDBCreate.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('create job with connect user success ', async () => { - const stubDBCreate = sinon.stub(Job, 'create').callsFake(() => { - return _.cloneDeep(jobResponseBody) - }) - const entity = await service.createJob(connectUser, jobRequestBody) - expect(entity).to.deep.eql(jobResponseBody.dataValues) - expect(stubDBCreate.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('create job with connect user failed user id not exist ', async () => { - stubGetUserId.restore() - stubGetUserId = sinon.stub(helper, 'getUserId').callsFake(() => { - throw new errors.NotFoundError('user id not found') - }) - - try { - await service.createJob(_.assign({}, connectUser, { userId: 'not_exist' }), jobRequestBody) - unexpected() - } catch (err) { - expect(err.message).to.equal('user id not found') - } - expect(stubIsConnectMember.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('create job with connect user failed ', async () => { - isConnectMember = false - try { - await service.createJob(topCoderUser, jobRequestBody) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - }) - - describe('get job test', () => { - it('get job success', async () => { - const jobResBody = _.cloneDeep(jobResponseBody) - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - return { - body: { - _id: jobResponseBody.dataValues.id, - _source: _.omit(jobResponseBody.dataValues, ['id']) - } - } - }) - const stubSearchCandidates = sinon.stub(esClient, 'search').callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: jobResponseBody.dataValues.candidates[0].id, - _source: _.omit(jobResponseBody.dataValues.candidates[0], ['id']) - }] - } - } - } - }) - const entity = await service.getJob(jobResponseBody.dataValues.id) - expect(entity).to.deep.eql(jobResBody.dataValues) - expect(stub.calledOnce).to.be.true - expect(stubSearchCandidates.calledOnce).to.be.true - }) - - it('get job with job not exist failed', async () => { - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - const err = new Error() - err.statusCode = 404 - throw err - }) - try { - await service.getJob(jobResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal(`id: ${jobResponseBody.dataValues.id} "Job" not found`) - expect(stub.calledOnce).to.be.true - } - }) - - it('get job from db success', async () => { - const jobResBody = _.cloneDeep(jobResponseBody) - const stub = sinon.stub(Job, 'findOne').callsFake(() => { - return jobResBody - }) - const entity = await service.getJob(jobResponseBody.dataValues.id, true) - expect(entity).to.deep.eql(jobResBody.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('get job from db with job not exist failed', async () => { - const stub = sinon.stub(Job, 'findOne').callsFake(() => { - return null - }) - try { - await service.getJob(jobResponseBody.dataValues.id, true) - unexpected() - } catch (error) { - expect(error.message).to.equal(`id: ${jobResponseBody.dataValues.id} "Job" doesn't exists.`) - expect(stub.calledOnce).to.be.true - } - }) - }) - - describe('fully update job test', () => { - it('fully update job test with booking manager success', async () => { - const jobResBody = _.cloneDeep(jobResponseBody) - const stub = sinon.stub(Job, 'findOne').onFirstCall().callsFake(() => { - return { - dataValues: { - projectId: '352123' - }, - update: () => { - return null - } - } - }).onSecondCall().callsFake(() => { - return jobResBody - }) - - const entity = await service.fullyUpdateJob(bookingManagerUser, jobResponseBody.dataValues.id, fullyUpdateJobRequestBody) - expect(entity).to.deep.eql(jobResBody.dataValues) - expect(stub.calledTwice).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('fully update job test with connect user success', async () => { - const jobResBody = _.cloneDeep(jobResponseBody) - const stub = sinon.stub(Job, 'findOne').onFirstCall().callsFake(() => { - return { - dataValues: { - projectId: '352123' - }, - update: () => { - return null - } - } - }).onSecondCall().callsFake(() => { - return jobResBody - }) - - const entity = await service.fullyUpdateJob(connectUser, jobResponseBody.dataValues.id, fullyUpdateJobRequestBody) - expect(entity).to.deep.eql(jobResBody.dataValues) - expect(stub.calledTwice).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('fully update job test with topcoder user failed', async () => { - isConnectMember = false - const stub = sinon.stub(Job, 'findOne').callsFake(() => { - return { - dataValues: { - projectId: 'not_exist' - } - } - }) - try { - await service.fullyUpdateJob(topCoderUser, jobResponseBody.dataValues.id, fullyUpdateJobRequestBody) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - expect(stub.calledOnce).to.be.true - }) - }) - - describe('partially update job test', () => { - it('partially update job with booking manager success', async () => { - const jobResBody = _.cloneDeep(jobResponseBody) - const stub = sinon.stub(Job, 'findOne').onFirstCall().callsFake(() => { - return { - dataValues: { - projectId: '352123' - }, - update: () => { - return null - } - } - }).onSecondCall().callsFake(() => { - return jobResBody - }) - - const entity = await service.partiallyUpdateJob(bookingManagerUser, jobResponseBody.dataValues.id, partiallyUpdateJobRequestBody) - expect(entity).to.deep.eql(jobResBody.dataValues) - expect(stub.calledTwice).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('partially update job with connect user success', async () => { - const jobResBody = _.cloneDeep(jobResponseBody) - const stub = sinon.stub(Job, 'findOne').onFirstCall().callsFake(() => { - return { - dataValues: { - projectId: '352123' - }, - update: () => { - return null - } - } - }).onSecondCall().callsFake(() => { - return jobResBody - }) - const entity = await service.partiallyUpdateJob(connectUser, jobResponseBody.dataValues.id, partiallyUpdateJobRequestBody) - expect(entity).to.deep.eql(jobResBody.dataValues) - expect(stub.calledTwice).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('partially update job with topcoder user failed', async () => { - isConnectMember = false - const stub = sinon.stub(Job, 'findOne').onFirstCall().callsFake(() => { - return { - dataValues: { - projectId: 'not_exist' - } - } - }) - try { - await service.partiallyUpdateJob(topCoderUser, jobResponseBody.dataValues.id, partiallyUpdateJobRequestBody) - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - expect(stub.calledOnce).to.be.true - }) - }) - - describe('delete job test', () => { - it('delete job test with booking manager success', async () => { - const stub = sinon.stub(Job, 'findOne').callsFake(() => { - return { - dataValues: { - projectId: '352123' - }, - update: () => { - return null - } - } - }) - await service.deleteJob(bookingManagerUser, jobResponseBody.dataValues.id) - expect(stub.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - - it('delete job test with connect user failed', async () => { - try { - await service.deleteJob(connectUser, jobResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - - it('delete job test with topcoder user failed', async () => { - try { - await service.deleteJob(topCoderUser, jobResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - }) - - describe('search jobs test', () => { - it('search jobs success', async () => { - const stub = sinon.stub(esClient, 'search').onFirstCall().callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: jobResponseBody.dataValues.id, - _source: _.omit(jobResponseBody.dataValues, ['id']) - }] - } - } - } - }).onSecondCall().callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: jobResponseBody.dataValues.candidates[0].id, - _source: _.omit(jobResponseBody.dataValues.candidates[0], ['id']) - }] - } - } - } - }) - const entity = await service.searchJobs({ sortBy: 'id', sortOrder: 'asc', page: 1, perPage: 1, skill: '56fdc405-eccc-4189-9e83-c78abf844f50', description: 'description 1', rateType: 'hourly' }) - expect(entity.result[0]).to.deep.eql(jobResponseBody.dataValues) - expect(stub.calledTwice).to.be.true - }) - - it('search jobs without query parameters success', async () => { - const stub = sinon.stub(esClient, 'search').onFirstCall().callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: jobResponseBody.dataValues.id, - _source: _.omit(jobResponseBody.dataValues, ['id']) - }] - } - } - } - }).onSecondCall().callsFake(() => { - return { - body: { - hits: { - total: { - value: 0 - }, - hits: [] - } - } - } - }) - const entity = await service.searchJobs({}) - expect(entity.result[0]).to.deep.eql(jobResponseBody.dataValues) - expect(stub.calledTwice).to.be.true - }) - - it('search jobs success when es search fails', async () => { - const stubESSearch = sinon.stub(esClient, 'search').callsFake(() => { - throw new Error('dedicated es failure') - }) - - const stubDBSearch = sinon.stub(Job, 'findAll').callsFake(() => { - return [jobResponseBody] - }) - - const entity = await service.searchJobs({ sortBy: 'id', sortOrder: 'asc', page: 1, perPage: 1, skill: '56fdc405-eccc-4189-9e83-c78abf844f50', description: 'description 1', rateType: 'hourly' }) - expect(entity.result[0]).to.deep.eql(jobResponseBody.dataValues) - expect(stubESSearch.calledOnce).to.be.true - expect(stubDBSearch.calledOnce).to.be.true - }) - }) -}) diff --git a/test/unit/ResourceBookingService.test.js b/test/unit/ResourceBookingService.test.js index fba2415a..08d219ba 100644 --- a/test/unit/ResourceBookingService.test.js +++ b/test/unit/ResourceBookingService.test.js @@ -2,42 +2,34 @@ process.env.NODE_ENV = 'test' require('../../src/bootstrap') -const _ = require('lodash') +// const _ = require('lodash') const expect = require('chai').expect const sinon = require('sinon') const models = require('../../src/models') const service = require('../../src/services/ResourceBookingService') -const { - bookingManagerUser, connectUser, topCoderUser, - jobCandidateResponseBody, resourceBookingRequestBody, - resourceBookingResponseBody, unexpected, - partiallyUpdateResourceBookingRequestBody, fullyUpdateResourceBookingRequestBody -} = require('./common/testData') - +const workPeriodService = require('../../src/services/WorkPeriodService') +const testData = require('./common/testData') const helper = require('../../src/common/helper') - -const esClient = helper.getESClient() +const eventHandlers = require('../../src/eventHandlers') +// const esClient = helper.getESClient() const busApiClient = helper.getBusApiClient() - const ResourceBooking = models.ResourceBooking - +const WorkPeriod = models.WorkPeriod +eventHandlers.init() describe('resourceBooking service test', () => { - let isConnectMember - let userId - let stubIsConnectMember - let stubGetUserId + let stubEnsureJobById + let stubEnsureUserById let stubPostEvent + let stubCreateWorkPeriodService + let stubUpdateWorkPeriodService + let stubDeleteWorkPeriodService beforeEach(() => { - isConnectMember = true - stubIsConnectMember = sinon.stub(helper, 'isConnectMember').callsFake(() => { - return isConnectMember - }) - - userId = 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a' - stubGetUserId = sinon.stub(helper, 'getUserId').callsFake(() => { - return userId - }) + stubEnsureJobById = sinon.stub(helper, 'ensureJobById').callsFake(async () => {}) + stubEnsureUserById = sinon.stub(helper, 'ensureUserById').callsFake(async () => testData.UserTCConnCopilot) stubPostEvent = sinon.stub(busApiClient, 'postEvent').callsFake(async () => {}) + stubCreateWorkPeriodService = sinon.stub(workPeriodService, 'createWorkPeriod').callsFake(async () => {}) + stubUpdateWorkPeriodService = sinon.stub(workPeriodService, 'partiallyUpdateWorkPeriod').callsFake(async () => {}) + stubDeleteWorkPeriodService = sinon.stub(workPeriodService, 'deleteWorkPeriod').callsFake(async () => {}) }) afterEach(() => { @@ -45,335 +37,210 @@ describe('resourceBooking service test', () => { }) describe('create resource booking test', () => { - it('create resource booking with booking manager success ', async () => { + it('create resource booking and auto populate work periods for 5 weeks', async () => { const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(() => { - return resourceBookingResponseBody + return testData.resourceBooking5Week.response }) - const entity = await service.createResourceBooking(bookingManagerUser, resourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingResponseBody.dataValues) + const entity = await service.createResourceBooking(testData.currentUser, testData.resourceBooking5Week.request) + expect(entity).to.deep.eql(testData.resourceBooking5Week.response.toJSON()) + expect(stubEnsureJobById.calledOnce).to.be.true + expect(stubEnsureUserById.calledOnce).to.be.true expect(stubDBCreate.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - }) - - it('create resource booking with connect user success ', async () => { - const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(() => { - return resourceBookingResponseBody - }) - - const entity = await service.createResourceBooking(connectUser, resourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingResponseBody.dataValues) + expect(stubCreateWorkPeriodService.callCount).to.eq(5) + expect(stubCreateWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBooking5Week.workPeriodRequests[0]) + expect(stubCreateWorkPeriodService.getCall(1).args[1]).to.deep.eq(testData.resourceBooking5Week.workPeriodRequests[1]) + expect(stubCreateWorkPeriodService.getCall(2).args[1]).to.deep.eq(testData.resourceBooking5Week.workPeriodRequests[2]) + expect(stubCreateWorkPeriodService.getCall(3).args[1]).to.deep.eq(testData.resourceBooking5Week.workPeriodRequests[3]) + expect(stubCreateWorkPeriodService.getCall(4).args[1]).to.deep.eq(testData.resourceBooking5Week.workPeriodRequests[4]) + }) + it('create resource booking and auto populate work periods for 1 week', async () => { + const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(async () => { + return testData.resourceBooking1Week.response + }) + + const entity = await service.createResourceBooking(testData.currentUser, testData.resourceBooking1Week.request) + expect(entity).to.deep.eql(testData.resourceBooking1Week.response.toJSON()) + expect(stubEnsureJobById.calledOnce).to.be.true + expect(stubEnsureUserById.calledOnce).to.be.true expect(stubDBCreate.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - expect(stubGetUserId.calledOnce).to.be.true - }) - - it('create resource booking with topcoder user failed ', async () => { - isConnectMember = false - try { - await service.createResourceBooking(topCoderUser, resourceBookingRequestBody) - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - }) - - describe('get resource booking test', () => { - it('get resource booking with booking manager success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - return { - body: { - _id: resourceBookingRes.dataValues.id, - _source: _.omit(resourceBookingRes.dataValues, ['id']) - } - } - }) - const entity = await service.getResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('get resource booking with connect user success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - return { - body: { - _id: resourceBookingRes.dataValues.id, - _source: _.omit(resourceBookingRes.dataValues, ['id']) - } - } - }) - - const entity = await service.getResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id) - expect(entity).to.deep.eql(_.omit(resourceBookingRes.dataValues, ['memberRate'])) - expect(stub.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - }) - - it('get resource booking with topcoder user success', async () => { - isConnectMember = false - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - return { - body: { - _id: resourceBookingRes.dataValues.id, - _source: _.omit(resourceBookingRes.dataValues, ['id']) - } - } - }) - const entity = await service.getResourceBooking(topCoderUser, resourceBookingResponseBody.dataValues.id) - expect(entity).to.deep.eql(_.omit(resourceBookingRes.dataValues, ['customerRate'])) - expect(stub.calledOnce).to.be.true - }) - - it('get resource booking with resource booking not exist success', async () => { - const stub = sinon.stub(esClient, 'get').callsFake(async () => { - const err = new Error() - err.statusCode = 404 - throw err - }) - try { - await service.getResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id) - } catch (error) { - expect(error.message).to.equal(`id: ${resourceBookingResponseBody.dataValues.id} "ResourceBooking" not found`) - expect(stub.calledOnce).to.be.true - } + expect(stubCreateWorkPeriodService.callCount).to.eq(1) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + expect(stubCreateWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBooking1Week.workPeriodRequests[0]) }) - - it('get resource booking from db with booking manager success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stub = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return resourceBookingRes + it('update resource booking and cause daysWorked to change', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBooking1Week.response }) - const entity = await service.getResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id, true) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('get resource booking from db with connect user success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stub = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return resourceBookingRes + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBooking1Week.workPeriodResponse }) - - const entity = await service.getResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id, true) - expect(entity).to.deep.eql(_.omit(resourceBookingRes.dataValues, ['memberRate'])) - expect(stub.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - }) - - it('get resource booking from db with topcoder user success', async () => { - isConnectMember = false - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stub = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return resourceBookingRes - }) - const entity = await service.getResourceBooking(topCoderUser, resourceBookingResponseBody.dataValues.id, true) - expect(entity).to.deep.eql(_.omit(resourceBookingRes.dataValues, ['customerRate'])) - expect(stub.calledOnce).to.be.true - }) - - it('get resource booking from db with resource booking not exist success', async () => { - const stub = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return null - }) - try { - await service.getResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id, true) - } catch (error) { - expect(error.message).to.equal(`id: ${resourceBookingResponseBody.dataValues.id} "ResourceBooking" doesn't exists.`) - expect(stub.calledOnce).to.be.true - } - }) - }) - - describe('fully update resource booking test', () => { - it('fully update resource booking test with booking manager success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ...resourceBookingRes, - update: () => { return null } - } - }) - const entity = await service.fullyUpdateResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id, fullyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + const entity = await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBooking1Week.response.dataValues.id, testData.resourceBooking1Week.updateRequest) + expect(entity).to.deep.eql(testData.resourceBooking1Week.updateResponse.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - }) - - it('fully update resource booking test with connect user success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ...resourceBookingRes, - update: () => { return null } - } - }) - - const entity = await service.fullyUpdateResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id, fullyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(1) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(testData.resourceBooking1Week.workPeriodUpdateRequests[0]) + }) + it('update resource booking and cause daysWorked to change', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse + }) + const entity = await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response.dataValues.id, testData.resourceBookingUpdate.updateRequest) + expect(entity).to.deep.eql(testData.resourceBookingUpdate.updateResponse.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - }) - - it('fully update resource booking test with topcoder user failed', async () => { - isConnectMember = false - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ...resourceBookingRes, - update: () => { return null } - } - }) - try { - await service.fullyUpdateResourceBooking(topCoderUser, resourceBookingResponseBody.dataValues.id, fullyUpdateResourceBookingRequestBody) - unexpected() - } catch (error) { - expect(stubResourceBookingFindOne.calledOnce).to.be.true - expect(error.message).to.equal('You are not allowed to perform this action!') - } - }) - }) - - describe('partially update resource booking test', () => { - it('partially update resource booking test with booking manager success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ...resourceBookingRes, - update: () => { return null } - } - }) - const entity = await service.partiallyUpdateResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id, partiallyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(1) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests[0]) + }) + it('update resource booking and cause workPeriod to create', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response2 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse + }) + const entity = await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response2.dataValues.id, testData.resourceBookingUpdate.updateRequest2) + expect(entity).to.deep.eql(testData.resourceBookingUpdate.updateResponse2.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - }) - - it('partially update resource booking test with connect user success', async () => { - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ...resourceBookingRes, - update: () => { return null } - } - }) - - const entity = await service.partiallyUpdateResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id, partiallyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(1) + expect(stubUpdateWorkPeriodService.callCount).to.eq(1) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests2[0]) + expect(stubCreateWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests2[1]) + }) + it('update resource booking and cause workPeriod to delete', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response3 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse + }) + const entity = await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response3.dataValues.id, testData.resourceBookingUpdate.updateRequest3) + expect(entity).to.deep.eql(testData.resourceBookingUpdate.updateResponse3.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.calledOnce).to.be.true - }) - - it('partially update resource booking test with topcoder user failed', async () => { - isConnectMember = false - const resourceBookingRes = _.cloneDeep(resourceBookingResponseBody) - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ...resourceBookingRes, - update: () => { return null } - } - }) + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(1) + expect(stubDeleteWorkPeriodService.callCount).to.eq(1) + expect(stubUpdateWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[0]) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[1]) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[2]) + }) + it('delete resource booking and cause workPeriod to delete', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response3 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse + }) + await service.deleteResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response3.dataValues.id) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(4) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[3]) + expect(stubDeleteWorkPeriodService.getCall(1).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[4]) + expect(stubDeleteWorkPeriodService.getCall(2).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[5]) + expect(stubDeleteWorkPeriodService.getCall(3).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests3[6]) + }) + it('update resource booking with paid weeks and cause workPeriod to delete', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response4 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse4 + }) + const entity = await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response4.dataValues.id, testData.resourceBookingUpdate.updateRequest4) + expect(entity).to.deep.eql(testData.resourceBookingUpdate.updateResponse4.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(1) + expect(stubDeleteWorkPeriodService.callCount).to.eq(2) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests4[0]) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests4[1]) + expect(stubDeleteWorkPeriodService.getCall(1).args[1]).to.deep.eq(testData.resourceBookingUpdate.workPeriodUpdateRequests4[2]) + }) + it('fail to update resource booking with paid weeks when try to delete paid weeks', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response4 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse4 + }) + let httpStatus try { - await service.partiallyUpdateResourceBooking(topCoderUser, resourceBookingResponseBody.dataValues.id, partiallyUpdateResourceBookingRequestBody) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') + await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response4.dataValues.id, testData.resourceBookingUpdate.updateRequest5) + } catch (err) { + httpStatus = err.httpStatus } - expect(stubResourceBookingFindOne.calledOnce).to.be.true - }) - }) - - describe('delete resource booking test', () => { - it('delete resource booking test with booking manager success', async () => { - const stubResourceBookingFindOne = sinon.stub(ResourceBooking, 'findOne').callsFake(() => { - return { - ..._.cloneDeep(resourceBookingResponseBody), - update: () => { return null } - } - }) - await service.deleteResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id) - expect(stubResourceBookingFindOne.calledOnce).to.be.true - expect(stubPostEvent.calledOnce).to.be.true - }) - - it('delete resource booking test with connect user failed', async () => { + expect(httpStatus).to.eq(400) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.calledOnce).to.be.false + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + }) + it('fail to update resource booking with paid weeks when try to set status cancelled', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response4 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse4 + }) + let httpStatus try { - await service.deleteResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') + await service.partiallyUpdateResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response4.dataValues.id, testData.resourceBookingUpdate.updateRequest6) + } catch (err) { + httpStatus = err.httpStatus } - }) - - it('delete resource booking test with topcoder user failed', async () => { + expect(httpStatus).to.eq(400) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.calledOnce).to.be.false + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + }) + it('fail to delete resource booking with paid weeks', async () => { + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return testData.resourceBookingUpdate.response4 + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return testData.resourceBookingUpdate.workPeriodResponse4 + }) + let httpStatus try { - await service.deleteResourceBooking(topCoderUser, jobCandidateResponseBody.dataValues.id) - unexpected() - } catch (error) { - expect(error.message).to.equal('You are not allowed to perform this action!') + await service.deleteResourceBooking(testData.currentUser, testData.resourceBookingUpdate.response4.dataValues.id) + } catch (err) { + httpStatus = err.httpStatus } - }) - }) - - describe('search resource booking test', () => { - it('search resource booking success', async () => { - const stub = sinon.stub(esClient, 'search').callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: resourceBookingResponseBody.dataValues.id, - _source: _.omit(resourceBookingResponseBody.dataValues, ['id']) - }] - } - } - } - }) - const entity = await service.searchResourceBookings({ sortBy: 'id', sortOrder: 'asc', page: 1, perPage: 1, status: 'sourcing' }) - expect(entity.result[0]).to.deep.eql(resourceBookingResponseBody.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('search resource booking without query parameters success', async () => { - const stub = sinon.stub(esClient, 'search').callsFake(() => { - return { - body: { - hits: { - total: { - value: 1 - }, - hits: [{ - _id: resourceBookingResponseBody.dataValues.id, - _source: _.omit(resourceBookingResponseBody.dataValues, ['id']) - }] - } - } - } - }) - const entity = await service.searchResourceBookings({}) - expect(entity.result[0]).to.deep.eql(resourceBookingResponseBody.dataValues) - expect(stub.calledOnce).to.be.true - }) - - it('search resource booking success when es search fails', async () => { - const stubESSearch = sinon.stub(esClient, 'search').callsFake(() => { - throw new Error('dedicated es failure') - }) - - const stubDBSearch = sinon.stub(ResourceBooking, 'findAll').callsFake(() => { - return [resourceBookingResponseBody] - }) - const entity = await service.searchResourceBookings({ sortBy: 'id', sortOrder: 'asc', page: 1, perPage: 1, status: 'sourcing' }) - expect(entity.result[0]).to.deep.eql(resourceBookingResponseBody.dataValues) - expect(stubESSearch.calledOnce).to.be.true - expect(stubDBSearch.calledOnce).to.be.true + expect(httpStatus).to.eq(400) + expect(stubResourceBookingFindById.calledOnce).to.be.false + expect(stubPostEvent.calledOnce).to.be.false + expect(stubWorkPeriodFindAll.called).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) }) }) }) diff --git a/test/unit/TeamService.test.js b/test/unit/TeamService.test.js deleted file mode 100644 index 01244d75..00000000 --- a/test/unit/TeamService.test.js +++ /dev/null @@ -1,293 +0,0 @@ -/* eslint-disable no-unused-expressions */ -process.env.NODE_ENV = 'test' -require('../../src/bootstrap') - -const expect = require('chai').expect -const sinon = require('sinon') - -const service = require('../../src/services/TeamService') -const JobService = require('../../src/services/JobService') -const ResourceBookingService = require('../../src/services/ResourceBookingService') -const { - bookingManagerUser, - unexpected, - projectRequestBody, - userRequestBody, - memberRequestBody, - skillsRequestBody, - userSkillsRequestBody, - resourceBookingsRequestBody, - jobsRequestBody, - taasTeamItem0ResponseBody, - taasTeam9050ResponseBody, - jobDetailResponseBody -} = require('./common/testData') -const helper = require('../../src/common/helper') - -describe('Team service test', () => { - let stubGetProjects - let stubGetProjectById - let stubGetUsers - let stubGetMembers - let stubGetSkills - let stubGetUserSkill - let stubGetAssignedResourceBookings - let stubGetJobs - beforeEach(() => { - stubGetProjects = sinon.stub(helper, 'getProjects').callsFake(() => { - return projectRequestBody - }) - - stubGetProjectById = sinon.stub(helper, 'getProjectById').callsFake(() => { - return projectRequestBody[0] - }) - - stubGetUsers = sinon.stub(helper, 'getUsers').callsFake(() => { - return userRequestBody - }) - - stubGetMembers = sinon.stub(helper, 'getMembers').callsFake(() => { - return memberRequestBody - }) - - stubGetSkills = sinon.stub(helper, 'getSkills').callsFake(() => { - return skillsRequestBody - }) - - stubGetUserSkill = sinon.stub(helper, 'getUserSkill').callsFake(() => { - return userSkillsRequestBody - }) - - stubGetAssignedResourceBookings = sinon.stub(ResourceBookingService, 'searchResourceBookings').callsFake(() => { - return { result: resourceBookingsRequestBody } - }) - - stubGetJobs = sinon.stub(JobService, 'searchJobs').callsFake(() => { - return { result: jobsRequestBody } - }) - }) - - afterEach(() => { - sinon.restore() - }) - - describe('search teams test', () => { - beforeEach(() => { - stubGetAssignedResourceBookings.restore() - stubGetAssignedResourceBookings = sinon.stub(ResourceBookingService, 'searchResourceBookings').callsFake(() => { - return { result: resourceBookingsRequestBody } - }) - stubGetJobs.restore() - stubGetJobs = sinon.stub(JobService, 'searchJobs').callsFake(() => { - return { result: jobsRequestBody } - }) - }) - - it('search teams success ', async () => { - const entity = await service.searchTeams(bookingManagerUser) - expect(entity.length).to.equal(20) - expect(entity[0]).to.deep.eql(taasTeamItem0ResponseBody) - expect(stubGetProjects.calledOnce).to.be.true - expect(stubGetUsers.calledOnce).to.be.true - expect(stubGetMembers.called).to.be.true - expect(stubGetAssignedResourceBookings.calledOnce).to.be.true - expect(stubGetJobs.calledOnce).to.be.true - }) - - it('search teams success with no resourceBooking ', async () => { - stubGetAssignedResourceBookings.restore() - stubGetAssignedResourceBookings = sinon.stub(ResourceBookingService, 'searchResourceBookings').callsFake(() => { - return { result: [] } - }) - stubGetJobs.restore() - stubGetJobs = sinon.stub(JobService, 'searchJobs').callsFake(() => { - return { result: [] } - }) - - const entity = await service.searchTeams(bookingManagerUser) - expect(entity.length).to.equal(20) - expect(entity[0]).to.deep.eql({ - id: 9050, - name: 'sample', - weeklyCost: 0, - resources: [] - }) - expect(stubGetProjects.calledOnce).to.be.true - expect(stubGetAssignedResourceBookings.calledOnce).to.be.true - expect(stubGetJobs.calledOnce).to.be.true - }) - - it('search teams success with no null start date', async () => { - stubGetAssignedResourceBookings.restore() - stubGetAssignedResourceBookings = sinon.stub(ResourceBookingService, 'searchResourceBookings').callsFake(() => { - return { - result: [{ - projectId: 9050, - userId: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da212', - startDate: null, - endDate: null, - memberRate: 13.23, - customerRate: 13, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da212' - }] - } - }) - - const entity = await service.searchTeams(bookingManagerUser) - expect(entity.length).to.equal(20) - expect(stubGetProjects.calledOnce).to.be.true - expect(stubGetAssignedResourceBookings.calledOnce).to.be.true - expect(stubGetJobs.calledOnce).to.be.true - }) - - it('search teams success with no empty user infos', async () => { - stubGetAssignedResourceBookings.restore() - stubGetAssignedResourceBookings = sinon.stub(ResourceBookingService, 'searchResourceBookings').callsFake(() => { - return { - result: [{ - projectId: 9050, - userId: 'not exist', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da212', - startDate: null, - endDate: null, - memberRate: 13.23, - customerRate: 13, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da212' - }] - } - }) - - const entity = await service.searchTeams(bookingManagerUser) - expect(entity.length).to.equal(20) - expect(stubGetProjects.calledOnce).to.be.true - expect(stubGetAssignedResourceBookings.calledOnce).to.be.true - expect(stubGetJobs.calledOnce).to.be.true - }) - }) - - describe('get team by id test', () => { - beforeEach(() => { - stubGetUserSkill.restore() - stubGetUserSkill = sinon.stub(helper, 'getUserSkill').callsFake(() => { - return userSkillsRequestBody - }) - }) - - it('get team by id success ', async () => { - const entity = await service.getTeam(bookingManagerUser, 9050) - expect(entity).to.deep.eql(taasTeam9050ResponseBody) - expect(stubGetProjectById.calledOnce).to.be.true - expect(stubGetUsers.calledOnce).to.be.true - expect(stubGetMembers.called).to.be.true - expect(stubGetAssignedResourceBookings.calledOnce).to.be.true - expect(stubGetJobs.calledOnce).to.be.true - expect(stubGetSkills.calledOnce).to.be.true - expect(stubGetUserSkill.called).to.be.true - }) - - it('get team by id with no user skills', async () => { - stubGetUserSkill.restore() - stubGetUserSkill = sinon.stub(helper, 'getUserSkill').callsFake(() => { - return [] - }) - - const entity = await service.getTeam(bookingManagerUser, 9050) - expect(entity.resources[0].skillMatched).to.equal(0) - expect(stubGetProjectById.calledOnce).to.be.true - expect(stubGetAssignedResourceBookings.calledOnce).to.be.true - expect(stubGetJobs.calledOnce).to.be.true - }) - }) - - describe('get job by team id and job id test', () => { - beforeEach(() => { - stubGetUserSkill.restore() - stubGetUserSkill = sinon.stub(helper, 'getUserSkill').callsFake(() => { - return userSkillsRequestBody - }) - stubGetMembers.restore() - stubGetMembers = sinon.stub(helper, 'getMembers').callsFake(() => { - return memberRequestBody - }) - stubGetUsers.restore() - stubGetUsers = sinon.stub(helper, 'getUsers').callsFake(() => { - return userRequestBody - }) - }) - - it('get job detail by id success ', async () => { - const entity = await service.getTeamJob(bookingManagerUser, 9050, '1d9e8c1a-e653-4d31-a799-2685e41da212') - expect(entity).to.deep.eql(jobDetailResponseBody) - expect(stubGetJobs.calledOnce).to.be.true - expect(stubGetUsers.called).to.be.true - expect(stubGetMembers.called).to.be.true - expect(stubGetUserSkill.called).to.be.true - }) - - it('get job detail by not exist id success ', async () => { - const entity = await service.getTeamJob(bookingManagerUser, 9050, '1d9e8c1a-e653-4d31-a799-2685e41da999') - expect(entity).to.be.a('object') - expect(stubGetJobs.calledOnce).to.be.true - }) - - it('get job detail by invalid id ', async () => { - try { - await service.getTeamJob(bookingManagerUser, 9050, 'invalid') - unexpected() - } catch (error) { - expect(error.message).to.equal('"jobId" must be a valid GUID') - } - }) - - it('get team by id with no user skills', async () => { - stubGetUserSkill.restore() - stubGetUserSkill = sinon.stub(helper, 'getUserSkill').callsFake(() => { - return [] - }) - - const entity = await service.getTeamJob(bookingManagerUser, 9050, '1d9e8c1a-e653-4d31-a799-2685e41da212') - expect(entity.candidates[0].skillMatched).to.equal(0) - expect(stubGetJobs.calledOnce).to.be.true - expect(stubGetUsers.called).to.be.true - expect(stubGetMembers.called).to.be.true - expect(stubGetUserSkill.called).to.be.true - }) - - it('get job detail by id with photoURL ', async () => { - stubGetMembers.restore() - stubGetMembers = sinon.stub(helper, 'getMembers').callsFake(() => { - return [{ - userId: 8547893, - handleLower: 'sandrine_kuvalis98', - photoURL: 'https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg' - }] - }) - - const entity = await service.getTeamJob(bookingManagerUser, 9050, '1d9e8c1a-e653-4d31-a799-2685e41da212') - expect(entity.candidates[0].photo_url).to.be.a('string') - expect(stubGetJobs.calledOnce).to.be.true - expect(stubGetUsers.called).to.be.true - expect(stubGetMembers.called).to.be.true - expect(stubGetUserSkill.called).to.be.true - }) - - it('get job detail by id empty users ', async () => { - stubGetUsers.restore() - stubGetUsers = sinon.stub(helper, 'getUsers').callsFake(() => { - return [] - }) - - const entity = await service.getTeamJob(bookingManagerUser, 9050, '1d9e8c1a-e653-4d31-a799-2685e41da212') - expect(entity.candidates.length).to.equal(0) - }) - }) -}) diff --git a/test/unit/common/testData.js b/test/unit/common/testData.js index dc607ba5..8c145247 100644 --- a/test/unit/common/testData.js +++ b/test/unit/common/testData.js @@ -1,789 +1,505 @@ -const bookingManagerUser = { - roles: [ - 'Topcoder User', - 'copilot', - 'Connect Manager', - 'bookingmanager', - 'u-bahn' - ], - iss: 'https://api.topcoder.com', - handle: 'pshah_manager', - exp: 55530199259, - userId: '40152856', - iat: 1602136970, - email: 'vikas.agarwal+pshah_manager@topcoder.com', - jti: '83a7b1cd-15b7-4529-b3a1-7c2282bbc750', - isBookingManager: true, - jwtToken: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik5VSkZORGd4UlRVME5EWTBOVVkzTlRkR05qTXlRamxETmpOQk5UYzVRVUV3UlRFeU56TTJRUSJ9.eyJodHRwczovL3RvcGNvZGVyLWRldi5jb20vcm9sZXMiOlsiVG9wY29kZXIgVXNlciIsImNvcGlsb3QiLCJDb25uZWN0IE1hbmFnZXIiLCJib29raW5nbWFuYWdlciIsInUtYmFobiJdLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcklkIjoiNDAxNTI4NTYiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vaGFuZGxlIjoicHNoYWhfbWFuYWdlciIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS91c2VyX2lkIjoiYXV0aDB8NDAxNTI4NTYiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdGNzc28iOiI0MDE1Mjg1Nnw4MTM0ZjQ4ZWJlMTFhODQ4YTM3NTllNWVmOWU5MmYyMTQ2OTJlMjExMzA0MGM4MmI1ZDhmNTgxYzZkZmNjYzg4IiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL2FjdGl2ZSI6dHJ1ZSwibmlja25hbWUiOiJwc2hhaF9tYW5hZ2VyIiwibmFtZSI6InZpa2FzLmFnYXJ3YWwrcHNoYWhfbWFuYWdlckB0b3Bjb2Rlci5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvOTJhZmIyZjBlZDUyZmRmYWUxZjM3MTAyMWFlNjUwMTM_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZ2aS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyMC0xMC0yNFQwODoyODoyNC4xODRaIiwiZW1haWwiOiJ2aWthcy5hZ2Fyd2FsK3BzaGFoX21hbmFnZXJAdG9wY29kZXIuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXV0aC50b3Bjb2Rlci1kZXYuY29tLyIsInN1YiI6ImF1dGgwfDQwMTUyODU2IiwiYXVkIjoiQlhXWFVXbmlsVlVQZE4wMXQyU2UyOVR3MlpZTkdadkgiLCJpYXQiOjE2MDM1NDMzMzgsImV4cCI6MzMxNjA0NTI3MzgsIm5vbmNlIjoiUjFBMmN6WXVWVFptYmpaSFJHOTJWbDlEU1VKNlVsbHZRWGMzUkhoNVMzWldkV1pEY0ROWE1FWjFYdz09In0.2gPsqZTgS1rtiNa1USm3KPA6Xsv3TcHxuDFofgIbeOM' -} - -const connectUser = { - roles: [ - 'Topcoder User', - 'copilot', - 'Connect Manager', - 'u-bahn' - ], - iss: 'https://api.topcoder.com', - sub: 'connect_user', - exp: 55530199259, - userId: '8547899', - iat: 1602136970, - email: 'connectUser@topcoder.com', - jti: '83a7b1cd-15b7-4529-b3a1-7c2282bbc750', - isBookingManager: false, - jwtToken: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJDb25uZWN0IFVzZXIiXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXIuY29tIiwic3ViIjoiY29ubmVjdF91c2VyIiwiZXhwIjo1NTUzMDE5OTI1OSwidXNlcklkIjoiMzUyNjc5ODMiLCJpYXQiOjE2MDIxMzY5NzAsImVtYWlsIjoiY29ubmVjdFVzZXJAdG9wY29kZXIuY29tIiwianRpIjoiODNhN2IxY2QtMTViNy00NTI5LWIzYTEtN2MyMjgyYmJjNzUwIn0.-rtF-_QhU-jDbxBqs79AP_4xFKp_gfVtptcuOmI7RUM' -} - -const topCoderUser = { - roles: [ - 'Topcoder User' - ], - iss: 'https://api.topcoder.com', - handle: 'topcoder_user', - exp: 55530199259, - userId: '8547899', - iat: 1602136970, - email: 'topcoderUser@topcoder.com', - jti: '83a7b1cd-15b7-4529-b3a1-7c2282bbc750', - isBookingManager: false, - jwtToken: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik5VSkZORGd4UlRVME5EWTBOVVkzTlRkR05qTXlRamxETmpOQk5UYzVRVUV3UlRFeU56TTJRUSJ9.eyJodHRwczovL3RvcGNvZGVyLWRldi5jb20vcm9sZXMiOlsiVG9wY29kZXIgVXNlciJdLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcklkIjoiODU0Nzg5OSIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS9oYW5kbGUiOiJwc2hhaF9tYW5hZ2VyIiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL3VzZXJfaWQiOiJhdXRoMHw0MDE1Mjg1NiIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS90Y3NzbyI6IjQwMTUyODU2fDgxMzRmNDhlYmUxMWE4NDhhMzc1OWU1ZWY5ZTkyZjIxNDY5MmUyMTEzMDQwYzgyYjVkOGY1ODFjNmRmY2NjODgiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vYWN0aXZlIjp0cnVlLCJuaWNrbmFtZSI6InBzaGFoX21hbmFnZXIiLCJuYW1lIjoidmlrYXMuYWdhcndhbCtwc2hhaF9tYW5hZ2VyQHRvcGNvZGVyLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci85MmFmYjJmMGVkNTJmZGZhZTFmMzcxMDIxYWU2NTAxMz9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRnZpLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDIwLTEwLTI0VDA4OjI4OjI0LjE4NFoiLCJlbWFpbCI6InZpa2FzLmFnYXJ3YWwrcHNoYWhfbWFuYWdlckB0b3Bjb2Rlci5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnRvcGNvZGVyLWRldi5jb20vIiwic3ViIjoiYXV0aDB8NDAxNTI4NTYiLCJhdWQiOiJCWFdYVVduaWxWVVBkTjAxdDJTZTI5VHcyWllOR1p2SCIsImlhdCI6MTYwMzU0MzMzOCwiZXhwIjozMzE2MDQ1MjczOCwibm9uY2UiOiJSMUEyY3pZdVZUWm1ialpIUkc5MlZsOURTVUo2VWxsdlFYYzNSSGg1UzNaV2RXWkRjRE5YTUVaMVh3PT0ifQ.HbAisH30DLcbFNQeIifSzk1yhDmlGHNpPi9LSZbAowo' +const currentUser = { + userId: '00000000-0000-0000-0000-000000000000', + isMachine: true } - -const jobRequestBody = { - projectId: 21, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - numPositions: 13, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - '56fdc405-eccc-4189-9e83-c78abf844f50', - 'f91ae184-aba2-4485-a8cb-9336988c05ab', - 'edfc7b4f-636f-44bd-96fc-949ffc58e38b', - '4ca63bb6-f515-4ab0-a6bc-c2d8531e084f', - 'ee03c041-d53b-4c08-b7d9-80d7461da3e4' - ] +const UserTCConnCopilot = { + userId: '4709473d-f060-4102-87f8-4d51ff0b34c1', + handle: 'TCConnCopilot' } - -const jobResponseBody = { - dataValues: { - id: '36762910-4efa-4db4-9b2a-c9ab54c232ed', +const resourceBooking5Week = { + request: { projectId: 21, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - numPositions: 13, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - '56fdc405-eccc-4189-9e83-c78abf844f50', - 'f91ae184-aba2-4485-a8cb-9336988c05ab', - 'edfc7b4f-636f-44bd-96fc-949ffc58e38b', - '4ca63bb6-f515-4ab0-a6bc-c2d8531e084f', - 'ee03c041-d53b-4c08-b7d9-80d7461da3e4' - ], - status: 'sourcing', - createdAt: '2020-10-08T12:58:28.321Z', - createdBy: 'pshah_manager', - candidates: [ - { - id: '5d09b0fb-5164-4b8c-9d04-525e840741e9', - jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - status: 'open', - createdAt: '2020-10-08T12:59:16.426Z', - createdBy: 'pshah_manager' - } - ] - } -} - -const fullyUpdateJobRequestBody = { - projectId: 21, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - numPositions: 13, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - '3fa85f64-5717-4562-b3fc-2c963f66afa6', - 'cc41ddc4-cacc-4570-9bdb-1229c12b9784' - ], - status: 'sourcing' -} - -const partiallyUpdateJobRequestBody = { - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - numPositions: 13, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - '3fa85f64-5717-4562-b3fc-2c963f66afa6' - ], - status: 'sourcing' -} - -const jobCandidateRequestBody = { - jobId: jobResponseBody.dataValues.id, - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a' -} - -const jobCandidateResponseBody = { - dataValues: { - id: '6e69b20f-144e-4edd-b68e-bd21f37f4b3e', - jobId: '6093e58c-683d-4022-8482-5515e8345016', userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - createdAt: '2020-10-09T00:51:38.663Z', - createdBy: 'pshah_manager', - status: 'open' - } -} - -const fullyUpdateJobCandidateRequestBody = { - jobId: jobResponseBody.dataValues.id, - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - status: 'selected' -} - -const partiallyUpdateJobCandidateRequestBody = { - status: 'shortlist' -} - -const resourceBookingRequestBody = { - projectId: 21, - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - jobId: jobResponseBody.dataValues.id, - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - memberRate: 13.23, - customerRate: 13, - rateType: 'hourly' -} - -const resourceBookingResponseBody = { - dataValues: { - id: '520bb632-a02a-415e-9857-93b2ecbf7d60', - projectId: 21, - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - jobId: '6093e58c-683d-4022-8482-5515e8345016', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', + endDate: '2020-10-27T04:17:23.131Z', memberRate: 13.23, customerRate: 13, - rateType: 'hourly', - createdAt: '2020-10-09T04:24:01.048Z', - createdBy: 'pshah_manager', - status: 'sourcing' - } -} - -const fullyUpdateResourceBookingRequestBody = { - projectId: 21, - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - jobId: resourceBookingResponseBody.dataValues.jobId, - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - memberRate: 13.23, - customerRate: 13, - rateType: 'hourly', - status: 'assigned' -} - -const partiallyUpdateResourceBookingRequestBody = { - status: 'assigned', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-27T04:17:23.131Z', - memberRate: 13.23, - customerRate: 13, - rateType: 'hourly' -} - -const unexpected = () => { throw new Error('should not reach here') } - -const projectRequestBody = [ - { id: 9050, name: 'sample' }, - { id: 9056, name: 'Invitation Test Max' }, - { id: 9063, name: 'Project001{codejam}' }, - { id: 9072, name: 'Project Name Edited' }, - { id: 9080, name: 'sdfdf' }, - { id: 9081, name: 'Test' }, - { id: 9091, name: 'Test 1 Max' }, - { id: 9096, name: 'test 1' }, - { id: 9097, name: 'test 2' }, - { id: 9099, name: 'Test' }, - { id: 9101, name: 'testin vikasverma' }, - { id: 9102, name: 'Test' }, - { id: 9132, name: 'Copilot Invite Test Max' }, - { id: 9133, name: 'Test' }, - { id: 9138, name: 'Update node versions 5 {codejam}' }, - { id: 9153, name: 'y' }, - { id: 9155, name: 'error' }, - { id: 9157, name: '3950-vikasverma' }, - { id: 9175, name: 'project' }, - { id: 9176, name: 'Testing 4-24-20 at 4-20' } -] - -const userRequestBody = [ - { - id: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e', - handle: 'PE335869', - firstName: ' Peddaram', - lastName: ' Varalakshmi' - }, - { - id: '10803918-ded0-4906-9442-65dc8819de91', - handle: 'Gayathri_1994', - firstName: 'Gayathri', - lastName: 'Sekar' - }, - { - id: '5bd69a82-c2cb-476f-9462-0883d3b28b90', - handle: 'Sandrine_Kuvalis98', - firstName: 'Mekhi', - lastName: 'Tremblay' + rateType: 'hourly' }, - { - id: '460bddcd-3580-4f2a-bfe8-5ba6d8f6f6af', - handle: 'Lourdes0', - firstName: 'Larissa', - lastName: 'Sporer' - }, - { - id: '4f2dc463-e24b-4b4a-8cde-c0122fbfb8ac', - handle: 'Demond39', - firstName: 'Domenic', - lastName: 'Casper' - }, - { - id: '39203872-707a-41b8-a587-18cab2557632', - handle: 'testkeychng204', - firstName: 'Testing', - lastName: 'Mithun' - }, - { - id: 'b074236c-bb33-449f-9320-72437a064c38', - handle: 'MA40018690', - firstName: 'Mangasamudram', - lastName: 'Teja' - }, - { - id: 'cdaeb417-e400-4df1-b484-f99ae10b4800', - handle: 'Leilani_Fahey35', - firstName: 'Godfrey', - lastName: 'Morar' - }, - { - id: 'ecec4ad8-3a1d-4646-8641-25054e8f2d33', - handle: 'Bernadine17', - firstName: 'Elmore', - lastName: 'Sanford' - }, - { - id: '28df7acf-d7b1-467c-8ee5-594c7bace8dc', - handle: 'Sylvan_Gorczany', - firstName: 'Samara', - lastName: 'Schultz' - }, - { - id: '6910d2f4-a50a-4494-8f46-6de1f3d032c2', - handle: 'Aditya65', - firstName: 'Clemens', - lastName: 'Rodriguez' - }, - { - id: '9bf08a13-29b6-4ef9-a2b6-d967c1c50fb4', - handle: 'Abirami_S', - firstName: 'Abirami', - lastName: 'SenthilNathan' + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-09-27T04:17:23.131Z', + endDate: '2020-10-27T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing' + } }, - { - id: '25f7b0e8-10a1-4bbc-b2f9-dacb1c72f1e9', - handle: 'Gaurav..Kumar', - firstName: 'Gaurav', - lastName: 'Kumar' + workPeriodRequests: [{ + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-09-27', + endDate: '2020-10-03', + daysWorked: 5, + paymentStatus: 'pending' }, { - id: '6fa6d708-68a6-47be-9591-4b5100921b3a', - handle: 'Kian.DuBuque', - firstName: 'Myles', - lastName: 'Connelly' + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-10-04', + endDate: '2020-10-10', + daysWorked: 5, + paymentStatus: 'pending' }, { - id: '8edca7c4-0e71-4688-952a-42227f73ca32', - handle: 'BinoyVipin', - firstName: 'Binoy', - lastName: 'V' + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-10-11', + endDate: '2020-10-17', + daysWorked: 5, + paymentStatus: 'pending' }, { - id: '247aaea8-f7e0-4ac8-b89e-4d78b76226b0', - handle: 'saikrupa87', - firstName: 'Miriyala', - lastName: 'Saikrupa reddy' + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-10-18', + endDate: '2020-10-24', + daysWorked: 5, + paymentStatus: 'pending' }, { - id: 'cc7a694c-44a0-412b-9d1d-f98f7fe26a21', - handle: 'SriV_1672', - firstName: 'Srinivas', - lastName: 'Merugu' + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-10-25', + endDate: '2020-10-31', + daysWorked: 2, + paymentStatus: 'pending' + }] +} +resourceBooking5Week.response.toJSON = function () { + return resourceBooking5Week.response.dataValues +} +const resourceBooking1Week = { + request: { + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', + startDate: '2020-11-20T04:17:23.131Z', + endDate: '2020-11-21T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly' }, - { - id: '07744775-eff1-443d-b56b-9d09ed02e599', - handle: 'Aachal', - firstName: 'Aachal ', - lastName: 'Jain' + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-11-20T04:17:23.131Z', + endDate: '2020-11-21T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing' + } }, - { - id: '0668fe37-b9cf-481b-8769-c3615833f80a', - handle: 'satadipa', - firstName: 'Satadipa', - lastName: 'Datta' + workPeriodRequests: [{ + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-11-15', + endDate: '2020-11-21', + daysWorked: 2, + paymentStatus: 'pending' + }], + workPeriodResponse: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-11-15', + endDate: '2020-11-21', + daysWorked: 2, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }], + updateRequest: { + startDate: '2020-11-18T04:17:23.131Z' }, - { - id: '844fad5d-f19e-444b-be2e-ba9c36d34265', - handle: 'BA249730', - firstName: 'Balamurali', - lastName: 'B' - } -] - -const memberRequestBody = [ - { - userId: 305384, - handleLower: 'mess', - photoURL: 'https://topcoder-dev-media.s3.us-east-1.amazonaws.com/member/profile/mess-1601487458118.jpeg' + updateResponse: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: new Date('2020-11-18T04:17:23.131Z'), + endDate: '2020-11-21T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + updatedBy: '00000000-0000-0000-0000-000000000000', + status: 'sourcing' + } }, - { - userId: 88773829, - handleLower: 'pe335869' + workPeriodUpdateRequests: [{ + daysWorked: 4 + }] +} +resourceBooking1Week.response.toJSON = function () { + return resourceBooking1Week.response.dataValues +} +resourceBooking1Week.updateResponse.toJSON = function () { + return resourceBooking1Week.updateResponse.dataValues +} +resourceBooking1Week.response.update = function () { + return resourceBooking1Week.updateResponse +} +const resourceBookingUpdate = { + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-08-20T04:17:23.131Z', + endDate: '2020-09-10T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing' + } }, - { - userId: 8547899, - handleLower: 'tonyj', - photoURL: 'https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg' + workPeriodResponse: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-08-16', + endDate: '2020-08-22', + daysWorked: 2, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }, { + id: 'b18398fe-09d0-4671-95b9-a4f56e6c6879', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-08-23', + endDate: '2020-08-29', + daysWorked: 5, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }, { + id: 'de811f42-cae7-4cb7-8893-d1e1f83b998f', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-08-30', + endDate: '2020-09-05', + daysWorked: 5, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }, { + id: '171e7f32-36fd-4969-9a99-036ced807d53', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-09-06', + endDate: '2020-09-12', + daysWorked: 4, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }], + updateRequest: { + endDate: '2020-09-12T04:17:23.131Z' }, - { - userId: 8547893, - handleLower: 'gayathri_1994', - photoURL: 'https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg' - } -] - -const skillsRequestBody = [ - { id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', name: 'ACI Concrete Strength Testing Technician' }, - { id: '59ee7b42-f3f3-48c9-bdca-e8396b241793', name: '2D Computer Graphics' }, - { id: '1b585c26-2649-4078-8369-b599fe6a9d75', name: 'ACCP Certified' }, - { id: '8b757998-ff7d-4b3a-9fee-a49d3e41da03', name: '3D Projection' }, - { id: 'bcfc8806-cae6-47ff-b0c9-f604acfc8c99', name: '35 Mm Films' }, - { id: 'db4358f3-c9a3-4afd-94a4-2d352d6bfa60', name: 'Nintex Workflow for SharePoint' }, - { id: '077533be-8029-4585-8b8e-9efc2dc43f53', name: 'CA Service Virtualization' }, - { id: 'f682838c-a9a7-4b47-8c2e-45d5132c04d7', name: 'SOAP UI Testing' }, - { id: '13dda8dc-4c34-4751-bbab-aab76d757cbb', name: 'JavaBean' }, - { id: '99b930b5-1b91-4df1-8b17-d9307107bb51', name: 'Excel' }, - { id: '513ba597-5ad1-4177-8556-35583e0cc6ac', name: 'Microsoft Dynamics 365 Portals' }, - { id: 'ee4c50c1-c8c3-475e-b6b6-edbd136a19d6', name: 'SFDC Lightening Components' }, - { id: '1c67b60d-32a3-4dcd-8bc4-947bc476fcd1', name: 'Performance Point' }, - { id: '70834003-3eba-452c-9bc4-a6d9d637a10e', name: 'AI/ML App Testing' }, - { id: '89139c80-d0a2-47c2-aa16-14589d5afd10', name: 'User Testing' }, - { id: '866ee344-5328-4c1d-b9ae-1c003f8fef16', name: 'DB2 Testing' }, - { id: '9f2d9127-6a2e-4506-ad76-c4ab63577b09', name: 'IndexedDB' }, - { id: 'c854ab55-5922-4be1-8ecc-b3bc1f8629af', name: 'InVision' }, - { id: '9515e7ee-83b6-49d1-ba5c-6c59c5a8ef1b', name: 'List' }, - { id: '57ef43c2-4227-4ea1-bc5a-287321f3f8b2', name: 'Microsoft Dynamics AX 2012 - Retail' } -] - -const userSkillsRequestBody = [ - { id: '5d313a7b-795b-42a2-9e7e-dc5e81c2f2b5', name: 'Java' }, - { id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', name: 'ACI Concrete Strength Testing Technician' } -] - -const resourceBookingsRequestBody = [ - { - projectId: 9063, - userId: '4f2dc463-e24b-4b4a-8cde-c0122fbfb8ac', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da216', - startDate: '2020-09-28T04:17:23.131Z', - endDate: '2020-12-30T04:17:23.131Z', - memberRate: 13.23, - customerRate: 11.11, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da216' + updateResponse: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-08-20T04:17:23.131Z', + endDate: new Date('2020-09-12T04:17:23.131Z'), + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + updatedBy: '00000000-0000-0000-0000-000000000000', + status: 'sourcing' + } }, - { - projectId: 9056, - userId: '460bddcd-3580-4f2a-bfe8-5ba6d8f6f6af', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da215', - startDate: '2020-09-28T04:17:23.131Z', - endDate: '2020-12-30T04:17:23.131Z', - memberRate: 13.23, - customerRate: 156.7, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da215' + workPeriodUpdateRequests: [{ + daysWorked: 5 + }], + response2: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-08-20T04:17:23.131Z', + endDate: '2020-09-10T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing' + } }, - { - projectId: 9050, - userId: '5bd69a82-c2cb-476f-9462-0883d3b28b90', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da214', - startDate: '2020-09-28T04:17:23.131Z', - endDate: '2020-12-30T04:17:23.131Z', - memberRate: 13.23, - customerRate: 16.7, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da214' + updateRequest2: { + endDate: '2020-09-15T04:17:23.131Z' }, - { - projectId: 9050, - userId: '10803918-ded0-4906-9442-65dc8819de91', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da213', - startDate: '2020-09-22T04:17:23.131Z', - endDate: '2020-10-27T04:17:23.131Z', - memberRate: 13.23, - customerRate: 14.5, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da213' + updateResponse2: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-08-20T04:17:23.131Z', + endDate: new Date('2020-09-15T04:17:23.131Z'), + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + updatedBy: '00000000-0000-0000-0000-000000000000', + status: 'sourcing' + } }, - { - projectId: 9050, - userId: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e', - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da212', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2021-11-11T04:17:23.131Z', - memberRate: 13.23, - customerRate: 13, - rateType: 'hourly', - status: 'assigned', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '3d9e8c1a-e653-4d31-a799-2685e41da212' - } -] - -const jobsRequestBody = [ - { - projectId: 9063, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-10-09T04:17:23.131Z', - numPositions: 10, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - '1b585c26-2649-4078-8369-b599fe6a9d75', - 'bcfc8806-cae6-47ff-b0c9-f604acfc8c99' - ], - status: 'sourcing', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '1d9e8c1a-e653-4d31-a799-2685e41da215' + workPeriodUpdateRequests2: [{ + daysWorked: 5 + }, { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2020-09-13', + endDate: '2020-09-19', + daysWorked: 2, + paymentStatus: 'pending' + }], + response3: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-08-20T04:17:23.131Z', + endDate: '2020-09-10T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing' + } }, - { - projectId: 9063, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-17T04:17:23.131Z', - endDate: '2020-10-19T04:17:23.131Z', - numPositions: 20, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - '8b757998-ff7d-4b3a-9fee-a49d3e41da03', - 'bcfc8806-cae6-47ff-b0c9-f604acfc8c99' - ], - status: 'sourcing', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '1d9e8c1a-e653-4d31-a799-2685e41da214', - candidates: [ - { - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da214', - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - status: 'open', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '2d9e8c1a-e653-4d31-a799-2685e41da214' - } - ] + updateRequest3: { + startDate: '2020-08-25T04:17:23.131Z' }, - { - projectId: 9056, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-29T04:17:23.131Z', - endDate: '2020-10-17T04:17:23.131Z', - numPositions: 11, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - '59ee7b42-f3f3-48c9-bdca-e8396b241793', - 'bcfc8806-cae6-47ff-b0c9-f604acfc8c99' - ], - status: 'sourcing', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '1d9e8c1a-e653-4d31-a799-2685e41da213', - candidates: [ - { - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da213', - userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - status: 'open', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '2d9e8c1a-e653-4d31-a799-2685e41da213' - } - ] + updateResponse3: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: new Date('2020-08-25T04:17:23.131Z'), + endDate: '2020-09-10T04:17:23.131Z', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + updatedBy: '00000000-0000-0000-0000-000000000000', + status: 'sourcing' + } }, - { - projectId: 9050, - externalId: '1212', - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-10-17T04:17:23.131Z', - numPositions: 13, - resourceType: 'Dummy Resource Type', - rateType: 'hourly', - skills: [ - 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - '59ee7b42-f3f3-48c9-bdca-e8396b241793', - '1b585c26-2649-4078-8369-b599fe6a9d75', - '8b757998-ff7d-4b3a-9fee-a49d3e41da03', - 'bcfc8806-cae6-47ff-b0c9-f604acfc8c99' - ], - status: 'sourcing', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '1d9e8c1a-e653-4d31-a799-2685e41da212', - candidates: [ - { - jobId: '1d9e8c1a-e653-4d31-a799-2685e41da212', - userId: '5bd69a82-c2cb-476f-9462-0883d3b28b90', - status: 'open', - createdAt: '2020-11-11T04:17:23.131Z', - createdBy: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', - id: '2d9e8c1a-e653-4d31-a799-2685e41da212' - } - ] - } -] - -const taasTeamItem0ResponseBody = { - id: 9050, - name: 'sample', - weeklyCost: 29.7, - resources: [ - { - id: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e', - handle: 'PE335869', - firstName: ' Peddaram', - lastName: ' Varalakshmi' + workPeriodUpdateRequests3: [ + 'b18398fe-09d0-4671-95b9-a4f56e6c6879', { + daysWorked: 4 }, - { - id: '10803918-ded0-4906-9442-65dc8819de91', - handle: 'Gayathri_1994', - firstName: 'Gayathri', - lastName: 'Sekar', - photo_url: 'https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg' - }, - { - id: '5bd69a82-c2cb-476f-9462-0883d3b28b90', - handle: 'Sandrine_Kuvalis98', - firstName: 'Mekhi', - lastName: 'Tremblay' - } + '10faf505-d0e3-4d13-a817-7f1319625e91', + '10faf505-d0e3-4d13-a817-7f1319625e91', + 'b18398fe-09d0-4671-95b9-a4f56e6c6879', + 'de811f42-cae7-4cb7-8893-d1e1f83b998f', + '171e7f32-36fd-4969-9a99-036ced807d53' ], - startDate: new Date('2020-09-22T04:17:23.131Z'), - endDate: new Date('2021-11-11T04:17:23.131Z'), - totalPositions: 13 -} - -const taasTeam9050ResponseBody = { - id: 9050, - name: 'sample', - weeklyCost: 29.7, - resources: [ - { - id: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e', - handle: 'PE335869', - firstName: ' Peddaram', - lastName: ' Varalakshmi', + response4: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2020-08-20T04:17:23.131Z', + endDate: '2020-09-10T04:17:23.131Z', + memberRate: 13.23, customerRate: 13, - job: { - id: '1d9e8c1a-e653-4d31-a799-2685e41da212', - name: 'Dummy Description' - }, - skills: [ - { - id: '5d313a7b-795b-42a2-9e7e-dc5e81c2f2b5', - name: 'Java' - }, - { - id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - name: 'ACI Concrete Strength Testing Technician' - } - - ], - skillMatched: 1 - }, - { - id: '10803918-ded0-4906-9442-65dc8819de91', - handle: 'Gayathri_1994', - firstName: 'Gayathri', - lastName: 'Sekar', - customerRate: 14.5, - photo_url: 'https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg', - job: { - id: '1d9e8c1a-e653-4d31-a799-2685e41da213', - name: 'Dummy Description' - }, - skills: [ - { - id: '5d313a7b-795b-42a2-9e7e-dc5e81c2f2b5', - name: 'Java' - }, - { - id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - name: 'ACI Concrete Strength Testing Technician' - } - ], - skillMatched: 1 - }, - { - id: '5bd69a82-c2cb-476f-9462-0883d3b28b90', - handle: 'Sandrine_Kuvalis98', - firstName: 'Mekhi', - lastName: 'Tremblay', - customerRate: 16.7, - job: { - id: '1d9e8c1a-e653-4d31-a799-2685e41da214', - name: 'Dummy Description' - }, - skills: [ - { - id: '5d313a7b-795b-42a2-9e7e-dc5e81c2f2b5', - name: 'Java' - }, - { - id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - name: 'ACI Concrete Strength Testing Technician' - } - ], - skillMatched: 1 + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing' } - ], - startDate: new Date('2020-09-22T04:17:23.131Z'), - endDate: new Date('2021-11-11T04:17:23.131Z'), - jobs: [ - { - id: '1d9e8c1a-e653-4d31-a799-2685e41da212', - description: 'Dummy Description', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-10-17T04:17:23.131Z', - numPositions: 13, + }, + workPeriodResponse4: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-08-16', + endDate: '2020-08-22', + daysWorked: 2, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }, { + id: 'b18398fe-09d0-4671-95b9-a4f56e6c6879', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-08-23', + endDate: '2020-08-29', + daysWorked: 5, + memberRate: null, + customerRate: null, + paymentStatus: 'completed', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }, { + id: '89f89450-201c-42e3-a868-a87177b82584', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-08-30', + endDate: '2020-09-05', + daysWorked: 5, + memberRate: null, + customerRate: null, + paymentStatus: 'partially-completed', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }, { + id: '3907e916-efdc-49d3-b0ef-970ccf7d78b0', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2020-09-06', + endDate: '2020-09-12', + daysWorked: 4, + memberRate: null, + customerRate: null, + paymentStatus: 'pending', + createdBy: '00000000-0000-0000-0000-000000000000', + updatedBy: null, + createdAt: '2021-04-10T22:25:08.289Z', + updatedAt: '2021-04-10T22:25:08.289Z' + }], + updateRequest4: { + startDate: '2020-08-25T04:17:23.131Z', + endDate: '2020-09-05T04:17:23.131Z' + }, + updateResponse4: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: new Date('2020-08-25T04:17:23.131Z'), + endDate: new Date('2020-09-05T04:17:23.131Z'), + memberRate: 13.23, + customerRate: 13, rateType: 'hourly', - skills: [ - { - id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - name: 'ACI Concrete Strength Testing Technician' - }, - { - id: '59ee7b42-f3f3-48c9-bdca-e8396b241793', - name: '2D Computer Graphics' - }, - { - id: '1b585c26-2649-4078-8369-b599fe6a9d75', - name: 'ACCP Certified' - }, - { - id: '8b757998-ff7d-4b3a-9fee-a49d3e41da03', - name: '3D Projection' - }, - { - id: 'bcfc8806-cae6-47ff-b0c9-f604acfc8c99', - name: '35 Mm Films' - } - ], + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + updatedBy: '00000000-0000-0000-0000-000000000000', status: 'sourcing' } - ] + }, + workPeriodUpdateRequests4: [{ + daysWorked: 4 + }, '10faf505-d0e3-4d13-a817-7f1319625e91', '3907e916-efdc-49d3-b0ef-970ccf7d78b0'], + updateRequest5: { + startDate: '2020-08-24T04:17:23.131Z', + endDate: '2020-08-29T04:17:23.131Z' + }, + updateRequest6: { + status: 'cancelled' + } } - -const jobDetailResponseBody = { - id: '1d9e8c1a-e653-4d31-a799-2685e41da212', - description: 'Dummy Description', - candidates: [ - { - id: '5bd69a82-c2cb-476f-9462-0883d3b28b90', - handle: 'Sandrine_Kuvalis98', - firstName: 'Mekhi', - lastName: 'Tremblay', - resumeLink: null, - status: 'open', - skills: [ - { - id: '5d313a7b-795b-42a2-9e7e-dc5e81c2f2b5', - name: 'Java' - }, - { - id: 'cb01fd31-e8d2-4e34-8bf3-b149705de3e1', - name: 'ACI Concrete Strength Testing Technician' - } - ], - job: { - id: '1d9e8c1a-e653-4d31-a799-2685e41da214', - name: 'Dummy Description' - }, - skillMatched: 1, - customerRate: 16.7 - } - ] +resourceBookingUpdate.response.toJSON = function () { + return resourceBookingUpdate.response.dataValues +} +resourceBookingUpdate.updateResponse.toJSON = function () { + return resourceBookingUpdate.updateResponse.dataValues } +resourceBookingUpdate.response.update = function () { + return resourceBookingUpdate.updateResponse +} +resourceBookingUpdate.response2.toJSON = function () { + return resourceBookingUpdate.response2.dataValues +} +resourceBookingUpdate.updateResponse2.toJSON = function () { + return resourceBookingUpdate.updateResponse2.dataValues +} +resourceBookingUpdate.response2.update = function () { + return resourceBookingUpdate.updateResponse2 +} +resourceBookingUpdate.response3.toJSON = function () { + return resourceBookingUpdate.response3.dataValues +} +resourceBookingUpdate.updateResponse3.toJSON = function () { + return resourceBookingUpdate.updateResponse3.dataValues +} +resourceBookingUpdate.response3.update = function () { + return resourceBookingUpdate.updateResponse3 +} +resourceBookingUpdate.response3.destroy = function () { +} +resourceBookingUpdate.response4.toJSON = function () { + return resourceBookingUpdate.response4.dataValues +} +resourceBookingUpdate.updateResponse4.toJSON = function () { + return resourceBookingUpdate.updateResponse4.dataValues +} +resourceBookingUpdate.response4.update = function () { + return resourceBookingUpdate.updateResponse4 +} module.exports = { - bookingManagerUser, - connectUser, - topCoderUser, - jobRequestBody, - jobResponseBody, - fullyUpdateJobRequestBody, - partiallyUpdateJobRequestBody, - jobCandidateRequestBody, - jobCandidateResponseBody, - fullyUpdateJobCandidateRequestBody, - partiallyUpdateJobCandidateRequestBody, - resourceBookingRequestBody, - resourceBookingResponseBody, - fullyUpdateResourceBookingRequestBody, - partiallyUpdateResourceBookingRequestBody, - unexpected, - projectRequestBody, - userRequestBody, - memberRequestBody, - skillsRequestBody, - userSkillsRequestBody, - resourceBookingsRequestBody, - jobsRequestBody, - taasTeamItem0ResponseBody, - taasTeam9050ResponseBody, - jobDetailResponseBody + currentUser, + UserTCConnCopilot, + resourceBooking5Week, + resourceBooking1Week, + resourceBookingUpdate } diff --git a/test/unit/helper.test.js b/test/unit/helper.test.js index 5c4b3141..49d880cd 100644 --- a/test/unit/helper.test.js +++ b/test/unit/helper.test.js @@ -2,10 +2,8 @@ process.env.NODE_ENV = 'test' require('../../src/bootstrap') -const _ = require('lodash') const sinon = require('sinon') const rewire = require('rewire') -const request = require('superagent') const expect = require('chai').expect const helper = rewire('../../src/common/helper') @@ -17,101 +15,6 @@ describe('helper test', () => { sinon.restore() }) - describe('setResHeaders test', () => { - const req = { - protocol: 'http', - baseUrl: 'api/v5', - path: '/jobs', - get: () => { - return 'localhost:3000' - } - } - const res = { - set (key, value) { - this[key] = value - }, - get (key) { - return 'test' - } - } - - const result = { - total: 4, - page: 2, - perPage: 2 - - } - it('setResHeaders test', () => { - const temp = _.cloneDeep(res) - helper.setResHeaders(req, temp, result) - expect(_.omit(temp, ['get', 'set'])).to.eql({ - 'X-Prev-Page': 1, - 'X-Page': 2, - 'X-Per-Page': 2, - 'X-Total': 4, - 'X-Total-Pages': 2, - Link: '; rel="first", ; rel="last", ; rel="prev"', - 'Access-Control-Expose-Headers': 'test, X-Page, X-Per-Page, X-Total, X-Total-Pages, X-Prev-Page, X-Next-Page' - }) - }) - - it('setResHeaders test with totalPages > 0', () => { - const temp1 = _.assign({}, result, { total: 40 }) - const temp2 = _.cloneDeep(res) - helper.setResHeaders(req, temp2, temp1) - expect(_.omit(temp2, ['get', 'set'])).to.eql({ - 'X-Prev-Page': 1, - 'X-Next-Page': 3, - 'X-Page': 2, - 'X-Per-Page': 2, - 'X-Total': 40, - 'X-Total-Pages': 20, - Link: '; rel="first", ; rel="last", ; rel="prev", ; rel="next"', - 'Access-Control-Expose-Headers': 'test, X-Page, X-Per-Page, X-Total, X-Total-Pages, X-Prev-Page, X-Next-Page' - }) - }) - - it('setResHeaders test with page = 1 and res.get returns null', () => { - const temp1 = _.assign({}, result, { total: 40, page: 1 }) - const temp2 = _.assign({}, res, { get (key) { return null } }) - helper.setResHeaders(req, temp2, temp1) - expect(_.omit(temp2, ['get', 'set'])).to.eql({ - 'X-Next-Page': 2, - 'X-Page': 1, - 'X-Per-Page': 2, - 'X-Total': 40, - 'X-Total-Pages': 20, - Link: '; rel="first", ; rel="last", ; rel="next"', - 'Access-Control-Expose-Headers': 'X-Page, X-Per-Page, X-Total, X-Total-Pages, X-Prev-Page, X-Next-Page' - }) - }) - - it('setResHeaders test with total = 0', () => { - const temp1 = _.assign({}, result, { total: 0 }) - const temp2 = _.assign({}, res, { get (key) { return null } }) - helper.setResHeaders(req, temp2, temp1) - expect(_.omit(temp2, ['get', 'set'])).to.eql({ - 'X-Prev-Page': 1, - 'X-Page': 2, - 'X-Per-Page': 2, - 'X-Total': 0, - 'X-Total-Pages': 0, - 'Access-Control-Expose-Headers': 'X-Page, X-Per-Page, X-Total, X-Total-Pages, X-Prev-Page, X-Next-Page' - }) - }) - }) - - describe('clearObject test', () => { - it('clearObject test with null', () => { - expect(helper.clearObject(null)).to.be.undefined - }) - - it('clearObject test with array', () => { - const arr = [{ test: 'ok' }, { test: 'ok' }, { test: 'ok' }] - expect(helper.clearObject(arr)).to.eql(arr) - }) - }) - describe('autoWrapExpress test', () => { it('autoWrapExpress with sync function', () => { const fn = () => { return null } @@ -141,218 +44,4 @@ describe('helper test', () => { expect(res.fn).to.be.a('function') }) }) - - describe('isConnectMember test', () => { - it('isConnectMember return true', async () => { - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - return this - } - } - }) - const res = await helper.isConnectMember() - expect(res).to.be.true - }) - - it('isConnectMember return false', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - throw new Error() - } - return this - } - } - }) - const res = await helper.isConnectMember() - expect(res).to.be.false - }) - }) - - describe('getUserId test', () => { - const id = '9966a0cf-c1c9-457b-9a4b-e6d1f4cec88d' - it('getUserId return id', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: [{ id }] - } - } - return this - } - } - }) - helper.__set__('m2m', { - getMachineToken: function () { - return 'm2mToken' - } - }) - const res = await helper.getUserId(8547899) - expect(res).to.equal(id) - }) - - it('getUserId catch not found', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: [] - } - } - return this - } - } - }) - helper.__set__('m2m', { - getMachineToken: function () { - return 'm2mToken' - } - }) - try { - await helper.getUserId(44532) - } catch (err) { - expect(err.message).to.equal('userId: 44532 "user" not found') - } - }) - }) - - describe('getProjects test', () => { - it('getProjects return entity result', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: [{ id: 1001, name: 'name' }] - } - } - return this - } - } - }) - const res = await helper.getProjects('token') - expect(res).to.be.a('array') - }) - }) - - describe('getProjectById test', () => { - it('getProjectById return entity result', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: { id: 1001, name: 'name' } - } - } - return this - } - } - }) - - const res = await helper.getProjectById('token', 1001) - expect(res).to.be.a('object') - }) - }) - - describe('getUsers test', () => { - it('getUsers return entity result', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: [{ id: '1001', handle: 'handle', firstName: 'Bill', lastName: 'Gate' }] - } - } - return this - } - } - }) - - const res = await helper.getUsers('token') - expect(res).to.be.a('array') - }) - }) - - describe('getMembers test', () => { - it('getMembers return entity result', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: { id: '1001', name: 'name' } - } - } - return this - } - } - }) - - const res = await helper.getMembers('token', ['name1', 'name2']) - expect(res).to.be.a('object') - }) - }) - - describe('getSkills test', () => { - it('getSkills return entity result', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: [{ id: 1001, name: 'name' }] - } - } - return this - } - } - }) - const res = await helper.getSkills('token') - expect(res).to.be.a('array') - }) - }) - - describe('getUserSkill test', () => { - it('getUserSkill return entity result', async () => { - let i = 0 - sinon.stub(request, 'get').callsFake(() => { - return { - set: function () { - i++ - if (i === 3) { - return { - body: [{ id: 1001, skill: { name: 'name' } }] - } - } - return this - } - } - }) - const res = await helper.getUserSkill('token', '1001') - expect(res).to.be.a('array') - }) - }) }) From 667ed1b0e45e7f379bf4664799dc8fea7d424415 Mon Sep 17 00:00:00 2001 From: eisbilir <72204071+eisbilir@users.noreply.github.com> Date: Thu, 15 Apr 2021 13:33:33 +0300 Subject: [PATCH 2/5] Update ResourceBookingEventHandler.js fix async await foreach --- src/eventHandlers/ResourceBookingEventHandler.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eventHandlers/ResourceBookingEventHandler.js b/src/eventHandlers/ResourceBookingEventHandler.js index 3fc483fa..95947436 100644 --- a/src/eventHandlers/ResourceBookingEventHandler.js +++ b/src/eventHandlers/ResourceBookingEventHandler.js @@ -254,7 +254,7 @@ async function deleteWorkPeriods (payload) { * @returns {undefined} */ async function _createWorkPeriods (periods, resourceBookingId) { - Promise.all(_.forEach(periods, async period => await WorkPeriodService.createWorkPeriod(helper.getAuditM2Muser(), + await Promise.all(_.map(periods, async period => await WorkPeriodService.createWorkPeriod(helper.getAuditM2Muser(), { resourceBookingId: resourceBookingId, startDate: period.startDate, @@ -270,7 +270,7 @@ async function _createWorkPeriods (periods, resourceBookingId) { * @returns {undefined} */ async function _updateWorkPeriods (periods) { - Promise.all(_.forEach(periods, async period => await WorkPeriodService.partiallyUpdateWorkPeriod(helper.getAuditM2Muser(), + await Promise.all(_.map(periods, async period => await WorkPeriodService.partiallyUpdateWorkPeriod(helper.getAuditM2Muser(), period.id, { daysWorked: period.daysWorked @@ -283,7 +283,7 @@ async function _updateWorkPeriods (periods) { * @returns {undefined} */ async function _deleteWorkPeriods (workPeriods) { - Promise.all(_.forEach(workPeriods, + await Promise.all(_.map(workPeriods, async workPeriod => await WorkPeriodService.deleteWorkPeriod(helper.getAuditM2Muser(), workPeriod.id))) } From b0508e98f8e29c2ba72b063b9a63356a6ee5a797 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Fri, 16 Apr 2021 10:59:03 +0300 Subject: [PATCH 3/5] fix: allow startDate be same as endDate for RB --- src/services/ResourceBookingService.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index bde6101a..972729f1 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -165,9 +165,9 @@ createResourceBooking.schema = Joi.object().keys({ startDate: Joi.date().allow(null), endDate: Joi.date().when('startDate', { is: Joi.exist(), - then: Joi.date().allow(null).greater(Joi.ref('startDate') + then: Joi.date().allow(null).min(Joi.ref('startDate') ).messages({ - 'date.greater': 'endDate must be greater than startDate' + 'date.min': 'endDate cannot be earlier than startDate' }), otherwise: Joi.date().allow(null) }), @@ -222,9 +222,9 @@ partiallyUpdateResourceBooking.schema = Joi.object().keys({ startDate: Joi.date().allow(null), endDate: Joi.date().when('startDate', { is: Joi.exist(), - then: Joi.date().allow(null).greater(Joi.ref('startDate') + then: Joi.date().allow(null).min(Joi.ref('startDate') ).messages({ - 'date.greater': 'endDate must be greater than startDate' + 'date.min': 'endDate cannot be earlier than startDate' }), otherwise: Joi.date().allow(null) }), @@ -259,9 +259,9 @@ fullyUpdateResourceBooking.schema = Joi.object().keys({ startDate: Joi.date().allow(null).default(null), endDate: Joi.date().when('startDate', { is: Joi.exist(), - then: Joi.date().allow(null).default(null).greater(Joi.ref('startDate') + then: Joi.date().allow(null).default(null).min(Joi.ref('startDate') ).messages({ - 'date.greater': 'endDate must be greater than startDate' + 'date.min': 'endDate cannot be earlier than startDate' }), otherwise: Joi.date().allow(null).default(null) }), From 2c16affce5263ccb0391ac45e295440c8b5fd0a6 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Fri, 16 Apr 2021 11:01:13 +0300 Subject: [PATCH 4/5] fix: routes "/workPeriods" to "/work-periods" --- ...coder-bookings-api.postman_collection.json | 348 +++++++++--------- docs/swagger.yaml | 4 +- src/routes/WorkPeriodRoutes.js | 4 +- 3 files changed, 178 insertions(+), 178 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 771bbdfb..a80efc4e 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -2990,12 +2990,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", + "raw": "{{URL}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -3129,12 +3129,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -4023,12 +4023,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", + "raw": "{{URL}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -4159,12 +4159,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -4727,12 +4727,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?perPage=1&sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", + "raw": "{{URL}}/work-periods?perPage=1&sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -4825,12 +4825,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodIdForPaid}}", + "raw": "{{URL}}/work-periods/{{workPeriodIdForPaid}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodIdForPaid}}" ] } @@ -5311,12 +5311,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5360,12 +5360,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5407,12 +5407,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5454,12 +5454,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5501,12 +5501,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5548,12 +5548,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5595,12 +5595,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5642,12 +5642,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5689,12 +5689,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5736,12 +5736,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5783,12 +5783,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5830,12 +5830,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5877,12 +5877,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5924,12 +5924,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -5971,12 +5971,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -6018,12 +6018,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -6054,12 +6054,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6091,12 +6091,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodIdCreatedByM2M}}" ] } @@ -6128,12 +6128,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}?fromDb=true", + "raw": "{{URL}}/work-periods/{{workPeriodId}}?fromDb=true", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ], "query": [ @@ -6171,12 +6171,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6208,12 +6208,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6245,12 +6245,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -6338,12 +6338,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -6431,12 +6431,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -6511,12 +6511,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -6604,12 +6604,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -6706,12 +6706,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6752,12 +6752,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodIdCreatedByM2M}}" ] } @@ -6800,12 +6800,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6848,12 +6848,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6896,12 +6896,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6944,12 +6944,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -6992,12 +6992,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7040,12 +7040,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7088,12 +7088,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7136,12 +7136,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7184,12 +7184,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7232,12 +7232,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7280,12 +7280,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7328,12 +7328,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7376,12 +7376,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7424,12 +7424,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7470,12 +7470,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7516,12 +7516,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodIdCreatedByM2M}}" ] } @@ -7564,12 +7564,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7612,12 +7612,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7660,12 +7660,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7708,12 +7708,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7756,12 +7756,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7804,12 +7804,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7852,12 +7852,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7900,12 +7900,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7948,12 +7948,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -7996,12 +7996,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -8044,12 +8044,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -8092,12 +8092,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -8140,12 +8140,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -8186,12 +8186,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -8232,12 +8232,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodIdCreatedByM2M}}" ] } @@ -8280,12 +8280,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -8326,12 +8326,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId}}", + "raw": "{{URL}}/work-periods/{{workPeriodId}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId}}" ] } @@ -12511,12 +12511,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -12534,12 +12534,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_by_administrator}}" ] } @@ -12558,12 +12558,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -12660,12 +12660,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_by_administrator}}" ] } @@ -12706,12 +12706,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_by_administrator}}" ] } @@ -12752,12 +12752,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_by_administrator}}" ] } @@ -13770,12 +13770,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -13819,12 +13819,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -13842,12 +13842,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_member}}?projectId=16718", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}?projectId=16718", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_member}}" ], "query": [ @@ -13872,12 +13872,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?projectId=16718", + "raw": "{{URL}}/work-periods?projectId=16718", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -13975,12 +13975,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_member}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_member}}" ] } @@ -14023,12 +14023,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_member}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_member}}" ] } @@ -14071,12 +14071,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_member}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_member}}" ] } @@ -15087,12 +15087,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -15136,12 +15136,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ] } }, @@ -15159,12 +15159,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_connect_manager}}" ] } @@ -15183,12 +15183,12 @@ } ], "url": { - "raw": "{{URL}}/workPeriods?projectId=16843", + "raw": "{{URL}}/work-periods?projectId=16843", "host": [ "{{URL}}" ], "path": [ - "workPeriods" + "work-periods" ], "query": [ { @@ -15286,12 +15286,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_connect_manager}}" ] } @@ -15334,12 +15334,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_connect_manager}}" ] } @@ -15382,12 +15382,12 @@ } }, "url": { - "raw": "{{URL}}/workPeriods/{{workPeriodId_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "workPeriods", + "work-periods", "{{workPeriodId_created_for_connect_manager}}" ] } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4552f8a1..46abb8c5 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1347,7 +1347,7 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" - /workPeriods: + /work-periods: post: tags: - WorkPeriods @@ -1565,7 +1565,7 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" - /workPeriods/{id}: + /work-periods/{id}: get: tags: - WorkPeriods diff --git a/src/routes/WorkPeriodRoutes.js b/src/routes/WorkPeriodRoutes.js index 42e61de4..7f84b5b0 100644 --- a/src/routes/WorkPeriodRoutes.js +++ b/src/routes/WorkPeriodRoutes.js @@ -4,7 +4,7 @@ const constants = require('../../app-constants') module.exports = { - '/workPeriods': { + '/work-periods': { post: { controller: 'WorkPeriodController', method: 'createWorkPeriod', @@ -18,7 +18,7 @@ module.exports = { scopes: [constants.Scopes.READ_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] } }, - '/workPeriods/:id': { + '/work-periods/:id': { get: { controller: 'WorkPeriodController', method: 'getWorkPeriod', From d2f669aaa31af3f7f78697d83b03adf3191db40d Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Fri, 16 Apr 2021 11:05:12 +0300 Subject: [PATCH 5/5] chore: move MAX dates to migration script from common config --- config/default.js | 6 +----- ...0-populate-work-periods-for-resource-bookings.js | 13 +++++++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/config/default.js b/config/default.js index 27d25792..a15e1c28 100644 --- a/config/default.js +++ b/config/default.js @@ -135,9 +135,5 @@ module.exports = { // the URL where TaaS App is hosted TAAS_APP_URL: process.env.TAAS_APP_URL || 'https://platform.topcoder-dev.com/taas/myteams', // default time zone for Work Periods - WORK_PERIOD_TIME_ZONE: process.env.WORK_PERIOD_TIME_ZONE || 'America/New_York', - // maximum start date of resource bookings when populating work periods from existing resource bookings in migration script - MAX_START_DATE: process.env.MAX_START_DATE || '2100-12-31', - // maximum end date of resource bookings when populating work periods from existing resource bookings in migration script - MAX_END_DATE: process.env.MAX_END_DATE || '2100-12-31' + WORK_PERIOD_TIME_ZONE: process.env.WORK_PERIOD_TIME_ZONE || 'America/New_York' } diff --git a/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js b/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js index f9947e3d..03f7f786 100644 --- a/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js +++ b/migrations/2021-04-10-populate-work-periods-for-resource-bookings.js @@ -4,6 +4,11 @@ const _ = require('lodash') const helper = require('../src/common/helper') const { v4: uuid } = require('uuid') +// maximum start date of resource bookings when populating work periods from existing resource bookings in migration script +const MAX_START_DATE = process.env.MAX_START_DATE || '2100-12-31' +// maximum end date of resource bookings when populating work periods from existing resource bookings in migration script +const MAX_END_DATE = process.env.MAX_END_DATE || '2100-12-31' + /* * Populate WorkPeriods for ResourceBookings */ @@ -15,8 +20,8 @@ module.exports = { try { const resourceBookings = await ResourceBooking.findAll({ where: { - start_date: { [Op.lt]: new Date(config.MAX_START_DATE) }, - end_date: { [Op.lt]: new Date(config.MAX_END_DATE) } + start_date: { [Op.lt]: new Date(MAX_START_DATE) }, + end_date: { [Op.lt]: new Date(MAX_END_DATE) } } }) if (resourceBookings.length === 0) { @@ -57,8 +62,8 @@ module.exports = { const Op = Sequelize.Op const resourceBookings = await ResourceBooking.findAll({ where: { - start_date: { [Op.lt]: new Date(config.MAX_START_DATE) }, - end_date: { [Op.lt]: new Date(config.MAX_END_DATE) } + start_date: { [Op.lt]: new Date(MAX_START_DATE) }, + end_date: { [Op.lt]: new Date(MAX_END_DATE) } }, // include soft-deleted resourceBookings paranoid: false