diff --git a/app-constants.js b/app-constants.js
index 71f9dce1..37217f99 100644
--- a/app-constants.js
+++ b/app-constants.js
@@ -62,9 +62,10 @@ const Interviews = {
Completed: 'Completed',
Cancelled: 'Cancelled'
},
+ // key: template name in x.ai, value: duration
XaiTemplate: {
- '30MinInterview': '30-min-interview',
- '60MinInterview': '60-min-interview'
+ '30-minutes': 30,
+ '60-minutes': 60
}
}
diff --git a/config/default.js b/config/default.js
index 8db522af..56ad8263 100644
--- a/config/default.js
+++ b/config/default.js
@@ -153,7 +153,7 @@ module.exports = {
// SendGrid email template ID for interview invitation
INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID: process.env.INTERVIEW_INVITATION_SENDGRID_TEMPLATE_ID,
// The sender (aka `from`) email for invitation.
- INTERVIEW_INVITATION_SENDER_EMAIL: process.env.INTERVIEW_INVITATION_SENDER_EMAIL,
+ INTERVIEW_INVITATION_SENDER_EMAIL: process.env.INTERVIEW_INVITATION_SENDER_EMAIL || 'scheduler@topcoder.com',
// the URL where TaaS App is hosted
TAAS_APP_URL: process.env.TAAS_APP_URL || 'https://platform.topcoder-dev.com/taas/myteams',
// environment variables for Payment Service
diff --git a/config/email_template.config.js b/config/email_template.config.js
index 7de8ad80..01775ad8 100644
--- a/config/email_template.config.js
+++ b/config/email_template.config.js
@@ -63,17 +63,31 @@ module.exports = {
/* Request interview for a job candidate
*
- * - interviewType: the x.ai interview type. Example: "30-min-interview"
+ * - interviewType: the x.ai interview type. Example: "30-minutes"
+ * - interviewRound: the round of the interview. Example: 2
+ * - interviewDuration: duration of the interview, in minutes. Example: 30
+ * - interviewerList: The list of interviewer email addresses. Example: "first@attendee.com, second@attendee.com"
+ * - candidateId: the id of the jobCandidate. Example: "cc562545-7b75-48bf-87e7-50b3c57e41b1"
* - candidateName: Full name of candidate. Example: "John Doe"
* - jobName: The title of the job. Example: "TaaS API Misc Updates"
- * - customMessage: if it's needed, a custom message can be added to the end of email. Example: "I would like to invite you for an interview..."
*
* Template (defined in SendGrid):
- * Subject: '/{{interviewType}} tech interview with {{candidateName}} for {{jobName}} is requested by the Customer'
+ * Subject: '{{interviewType}} tech interview with {{candidateName}} for {{jobName}} is requested by the Customer'
* Body:
- * 'The customer has requested /{{interviewType}} with {{candidateName}} for {{jobName}}.'
- * + 'In a few minutes you will receive an invitation from our scheduling tool. Please proceed with the invitation to agree on timing.'
- * + '
{{customMessage}}'
+ * 'Hello!
+ *
+ * Congratulations, you have been selected to participate in a Topcoder Gig Work Interview!
+ *
+ * Please monitor your email for a response to this where you can coordinate your availability.
+ *
+ * Interviewee: {{candidateName}}
+ * Interviewer(s): {{interviewerList}}
+ * Interview Length: {{interviewDuration}} minutes
+ *
+ * /{{interviewType}}
+ *
+ * Topcoder Info:
+ * Note: "id: {{candidateId}}, round: {{interviewRound}}"'
*
* Note, that the template should be defined in SendGrid.
* The subject & body above (identical to actual SendGrid template) is for reference purposes.
diff --git a/data/demo-data.json b/data/demo-data.json
index 2947b5d3..5736c839 100644
--- a/data/demo-data.json
+++ b/data/demo-data.json
@@ -269,7 +269,7 @@
"id": "5191a860-4327-4c50-b76b-84beba04519b",
"jobId": "a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e",
"userId": "79ce2a3e-7679-48cf-8ac9-0a8ca4c4b463",
- "status": "shortlist",
+ "status": "selected",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -282,7 +282,7 @@
"id": "e6d9635c-b122-4f69-9285-09fb1ab30106",
"jobId": "a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e",
"userId": "98ec2c16-442e-4b61-8ad1-66123ee37d3c",
- "status": "rejected",
+ "status": "rejected - other",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -347,7 +347,7 @@
"id": "85d6649e-2682-4904-9480-a77b72fef27d",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
"userId": "213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e",
- "status": "selected",
+ "status": "placed",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -360,7 +360,7 @@
"id": "922dfce3-4e06-4387-9fdb-64f70675e86b",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
"userId": "dd5adacb-444d-4992-8b7b-0c349be598db",
- "status": "selected",
+ "status": "placed",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -373,7 +373,7 @@
"id": "c26c38e2-a47d-405b-abc6-fe62a739561c",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
"userId": "6d0509c7-5f12-4d84-9a19-8e80ef7ddd66",
- "status": "selected",
+ "status": "placed",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -386,7 +386,7 @@
"id": "7bef2b37-e1ee-4638-bfc1-c911787ac955",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
"userId": "f65e2104-2987-4136-839d-ee4632f0b2e5",
- "status": "selected",
+ "status": "placed",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -399,7 +399,7 @@
"id": "e9716139-1f40-4bf1-9f8a-77ae4bcc621e",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
"userId": "e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e",
- "status": "selected",
+ "status": "placed",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -412,7 +412,7 @@
"id": "a1731d01-eac9-4eff-8e5a-8a3c99bc66e0",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
"userId": "bef43122-426b-4b2b-acdd-9b5b3bd1c0bf",
- "status": "selected",
+ "status": "placed",
"externalId": null,
"resume": null,
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -425,7 +425,7 @@
"id": "25787cb2-d876-4883-b533-d5e628d213ce",
"jobId": "1324da27-9d7d-47d8-a04e-9fb3f35a67fa",
"userId": "95e7970f-12b4-43b7-ab35-38c34bf033c7",
- "status": "open",
+ "status": "interview",
"externalId": "88774631",
"resume": "http://example.com",
"createdBy": "57646ff9-1cd3-4d3c-88ba-eb09a395366c",
@@ -468,7 +468,7 @@
"projectId": 111,
"userId": "213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
- "status": "assigned",
+ "status": "placed",
"startDate": "2021-01-25",
"endDate": "2021-01-31",
"memberRate": 1000,
@@ -500,7 +500,7 @@
"projectId": 111,
"userId": "6d0509c7-5f12-4d84-9a19-8e80ef7ddd66",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
- "status": "assigned",
+ "status": "placed",
"startDate": "2021-02-27",
"endDate": "2021-03-15",
"memberRate": 2000,
@@ -532,7 +532,7 @@
"projectId": 111,
"userId": "dd5adacb-444d-4992-8b7b-0c349be598db",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
- "status": "assigned",
+ "status": "placed",
"startDate": "2021-03-18",
"endDate": "2021-05-28",
"memberRate": 800,
@@ -548,7 +548,7 @@
"projectId": 111,
"userId": "f65e2104-2987-4136-839d-ee4632f0b2e5",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
- "status": "assigned",
+ "status": "placed",
"startDate": "2000-03-27",
"endDate": "2000-04-27",
"memberRate": 3000,
@@ -564,7 +564,7 @@
"projectId": 111,
"userId": "bef43122-426b-4b2b-acdd-9b5b3bd1c0bf",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
- "status": "assigned",
+ "status": "placed",
"startDate": "2020-04-27",
"endDate": "2020-05-27",
"memberRate": 0,
@@ -612,7 +612,7 @@
"projectId": 111,
"userId": "e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e",
"jobId": "2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0",
- "status": "assigned",
+ "status": "placed",
"startDate": "2021-07-27",
"endDate": "2021-09-27",
"memberRate": 1700,
diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json
index f40394d5..704ad61d 100644
--- a/docs/Topcoder-bookings-api.postman_collection.json
+++ b/docs/Topcoder-bookings-api.postman_collection.json
@@ -1,6 +1,6 @@
{
"info": {
- "_postman_id": "f26164a2-4129-4e0a-89fb-75c6756b4a79",
+ "_postman_id": "059739c9-5726-44b6-876d-6d87940c9aff",
"name": "Topcoder-bookings-api",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
@@ -2088,7 +2088,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2153,7 +2153,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2218,7 +2218,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2283,7 +2283,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2348,7 +2348,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2413,7 +2413,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2476,7 +2476,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2539,7 +2539,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
},
{
@@ -2763,7 +2763,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n \"status\": \"shortlist\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
+ "raw": "{\n \"status\": \"selected\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
"options": {
"raw": {
"language": "json"
@@ -2796,7 +2796,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n \"status\": \"shortlist\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
+ "raw": "{\n \"status\": \"selected\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
"options": {
"raw": {
"language": "json"
@@ -2829,7 +2829,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n \"status\": \"shortlist\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
+ "raw": "{\n \"status\": \"selected\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
"options": {
"raw": {
"language": "json"
@@ -2862,7 +2862,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n \"status\": \"shortlist\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
+ "raw": "{\n \"status\": \"selected\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
"options": {
"raw": {
"language": "json"
@@ -2895,7 +2895,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n \"status\": \"shortlist\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
+ "raw": "{\n \"status\": \"selected\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
"options": {
"raw": {
"language": "json"
@@ -2928,7 +2928,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\n \"status\": \"shortlist\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
+ "raw": "{\n \"status\": \"selected\",\n \"externalId\": \"300234321\",\n \"resume\": \"http://example.com\"\n}",
"options": {
"raw": {
"language": "json"
@@ -3217,7 +3217,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"status\": \"Completed\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"status\": \"Completed\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3270,7 +3270,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"attendeesList\": [\"attendee1@yopmail.com\", \"attendee2@yopmail.com\"],\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"attendeesList\": [\"attendee1@yopmail.com\", \"attendee2@yopmail.com\"],\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3321,7 +3321,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3373,7 +3373,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3422,7 +3422,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"status\": \"xxxx\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"status\": \"xxxx\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3472,7 +3472,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"attendeesList\": [\"attendee1@yopmail.com\", \"attendee2@yopmail.com\"]\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"attendeesList\": [\"attendee1@yopmail.com\", \"attendee2@yopmail.com\"]\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3521,7 +3521,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"attendeesList\": \"asddd\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"attendeesList\": \"asddd\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3570,7 +3570,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"attendeesList\": [\"asdas\"]\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"attendeesList\": [\"asdas\"]\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3619,7 +3619,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"round\": 1\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"round\": 1\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3668,7 +3668,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"startTimestamp\": \"2021-04-17\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"startTimestamp\": \"2021-04-17\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3748,7 +3748,7 @@
"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(\"\\\"interview.xaiTemplate\\\" must be one of [30-min-interview, 60-min-interview]\")\r",
+ " pm.expect(response.message).to.eq(\"\\\"interview.xaiTemplate\\\" must be one of [30-minutes, 60-minutes]\")\r",
"});"
],
"type": "text/javascript"
@@ -3815,7 +3815,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3864,7 +3864,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3911,7 +3911,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -3958,7 +3958,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4005,7 +4005,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4052,7 +4052,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4101,7 +4101,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4150,7 +4150,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4199,7 +4199,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4248,7 +4248,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4297,7 +4297,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4340,7 +4340,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -4389,7 +4389,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -5312,7 +5312,7 @@
"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(\"\\\"data.xaiTemplate\\\" must be one of [30-min-interview, 60-min-interview]\")\r",
+ " pm.expect(response.message).to.eq(\"\\\"data.xaiTemplate\\\" must be one of [30-minutes, 60-minutes]\")\r",
"});"
],
"type": "text/javascript"
@@ -8467,7 +8467,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-26\",\r\n \"endDate\": \"2020-11-29\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-26\",\r\n \"endDate\": \"2020-11-29\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8603,7 +8603,7 @@
],
"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-27\",\r\n \"endDate\": \"2021-01-10\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-12-27\",\r\n \"endDate\": \"2021-01-10\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8741,7 +8741,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-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8789,7 +8789,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-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8837,7 +8837,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-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8885,7 +8885,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-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8931,7 +8931,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-30\",\r\n \"endDate\": \"2020-11-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-30\",\r\n \"endDate\": \"2020-11-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -8977,7 +8977,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-12-30\",\r\n \"endDate\": \"2021-02-10\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-12-30\",\r\n \"endDate\": \"2021-02-10\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -9025,7 +9025,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -9073,7 +9073,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -9121,7 +9121,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-28\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -9169,7 +9169,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -19214,7 +19214,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
}
]
@@ -19235,7 +19235,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"jobId\": \"{{job_id_created_by_administrator}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"status\": \"selected\"\r\n}",
+ "raw": "{\r\n \"jobId\": \"{{job_id_created_by_administrator}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"status\": \"placed\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -19268,7 +19268,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"shortlist\"\r\n}",
+ "raw": "{\r\n \"status\": \"selected\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -19449,7 +19449,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -19805,7 +19805,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{job_id_created_by_administrator}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{job_id_created_by_administrator}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -19838,7 +19838,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -21158,7 +21158,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
}
]
@@ -21179,7 +21179,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"status\": \"selected\"\r\n}",
+ "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"status\": \"placed\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -21212,7 +21212,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"shortlist\"\r\n}",
+ "raw": "{\r\n \"status\": \"selected\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -21389,7 +21389,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -21440,7 +21440,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -21845,7 +21845,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"projectId\": {{project_id_16718}},\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{project_id_16718}},\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -21878,7 +21878,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -23313,7 +23313,7 @@
},
{
"key": "status",
- "value": "shortlist",
+ "value": "selected",
"disabled": true
}
]
@@ -23334,7 +23334,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"status\": \"selected\"\r\n}",
+ "raw": "{\r\n \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"status\": \"placed\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -23367,7 +23367,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"shortlist\"\r\n}",
+ "raw": "{\r\n \"status\": \"selected\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -23544,7 +23544,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -23595,7 +23595,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"xaiTemplate\": \"30-min-interview\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
+ "raw": "{\r\n \"xaiTemplate\": \"30-minutes\",\r\n \"googleCalendarId\": \"dummyId\",\r\n \"customMessage\": \"This is a custom message\",\r\n \"status\": \"Scheduling\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -23996,7 +23996,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"projectId\": {{project_id_16843}},\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"projectId\": {{project_id_16843}},\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"placed\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
@@ -24029,7 +24029,7 @@
],
"body": {
"mode": "raw",
- "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
+ "raw": "{\r\n \"status\": \"placed\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-09-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}",
"options": {
"raw": {
"language": "json"
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index d96dd455..93b67407 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -593,9 +593,11 @@ paths:
enum:
[
"open",
+ "placed",
"selected",
- "shortlist",
- "rejected",
+ "client rejected - screening",
+ "client rejected - interview",
+ "rejected - other",
"cancelled",
"interview",
"topcoder-rejected",
@@ -1305,7 +1307,7 @@ paths:
required: false
schema:
type: string
- enum: ["assigned", "in-progress", "completed"]
+ enum: ["placed", "in-progress", "completed"]
description: The status.
- in: query
name: startDate
@@ -3283,9 +3285,11 @@ components:
enum:
[
"open",
+ "placed",
"selected",
- "shortlist",
- "rejected",
+ "client rejected - screening",
+ "client rejected - interview",
+ "rejected - other",
"cancelled",
"interview",
"topcoder-rejected",
@@ -3392,7 +3396,7 @@ components:
description: "The user id."
status:
type: string
- enum: ["open", "selected", "shortlist", "rejected", "cancelled"]
+ enum: ["open", "placed", "selected", "client rejected - screening", "client rejected - interview", "rejected - other", "cancelled", "interview", "topcoder-rejected"]
description: "The job candidate status."
default: open
externalId:
@@ -3410,9 +3414,11 @@ components:
enum:
[
"open",
+ "placed",
"selected",
- "shortlist",
- "rejected",
+ "client rejected - screening",
+ "client rejected - interview",
+ "rejected - other",
"cancelled",
"interview",
"topcoder-rejected",
@@ -3449,8 +3455,8 @@ components:
description: "The google calendar id."
xaiTemplate:
type: string
- example: "30-min-interview"
- enum: ["30-min-interview", "60-min-interview"]
+ example: "30-minutes"
+ enum: ["30-minutes", "60-minutes"]
description: "The x.ai template name"
customMessage:
type: string
@@ -3504,8 +3510,8 @@ components:
description: "The custom message."
xaiTemplate:
type: string
- enum: ["30-min-interview", "60-min-interview"]
- example: "30-min-interview"
+ enum: ["30-minutes", "60-minutes"]
+ example: "30-minutes"
description: "The x.ai template name"
attendeesList:
type: array
@@ -3529,8 +3535,8 @@ components:
description: "The custom message."
xaiTemplate:
type: string
- enum: ["30-min-interview", "60-min-interview"]
- example: "30-min-interview"
+ enum: ["30-minutes", "60-minutes"]
+ example: "30-minutes"
description: "The x.ai template name"
attendeesList:
type: array
@@ -3617,7 +3623,7 @@ components:
description: "The external id."
status:
type: string
- enum: ["assigned", "closed", "cancelled"]
+ enum: ["placed", "closed", "cancelled"]
description: "The job status."
startDate:
type: string
@@ -3684,7 +3690,7 @@ components:
description: "The job id."
status:
type: string
- enum: ["assigned", "closed", "cancelled"]
+ enum: ["placed", "closed", "cancelled"]
description: "The job status."
default: sourcing
startDate:
@@ -3719,7 +3725,7 @@ components:
properties:
status:
type: string
- enum: ["assigned", "closed", "cancelled"]
+ enum: ["placed", "closed", "cancelled"]
startDate:
type: string
format: date
@@ -4338,14 +4344,20 @@ components:
type: string
format: url
description: "The link for the resume that can be downloaded"
+ interviews:
+ type: array
+ items:
+ $ref: "#/components/schemas/Interview"
status:
type: string
enum:
[
"open",
+ "placed",
"selected",
- "shortlist",
- "rejected",
+ "client rejected - screening",
+ "client rejected - interview",
+ "rejected - other",
"cancelled",
"interview",
"topcoder-rejected",
diff --git a/migrations/2021-04-27-172352-resource-booking-placed-status-migration.js b/migrations/2021-04-27-172352-resource-booking-placed-status-migration.js
new file mode 100644
index 00000000..70ae3c6c
--- /dev/null
+++ b/migrations/2021-04-27-172352-resource-booking-placed-status-migration.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const config = require('config')
+
+/**
+ * Migrate ResourceBooking status - from assigned to placed.
+ */
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.resource_bookings`
+ await queryInterface.sequelize.query(`UPDATE ${tableName} SET status = 'placed' WHERE status = 'assigned'`)
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.resource_bookings`
+ await queryInterface.sequelize.query(`UPDATE ${tableName} SET status = 'assigned' WHERE status = 'placed'`)
+ }
+};
diff --git a/migrations/2021-04-27-172407-job-candidate-placed-status-migration.js b/migrations/2021-04-27-172407-job-candidate-placed-status-migration.js
new file mode 100644
index 00000000..611184ee
--- /dev/null
+++ b/migrations/2021-04-27-172407-job-candidate-placed-status-migration.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const config = require('config')
+
+/**
+ * Migrate JobCandidate status - from selected to placed.
+ */
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.job_candidates`
+ await queryInterface.sequelize.query(`UPDATE ${tableName} SET status = 'placed' WHERE status = 'selected'`)
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.job_candidates`
+ await queryInterface.sequelize.query(`UPDATE ${tableName} SET status = 'selected' WHERE status = 'placed'`)
+ }
+};
diff --git a/migrations/2021-04-27-172422-job-candidate-selected-status-migration.js b/migrations/2021-04-27-172422-job-candidate-selected-status-migration.js
new file mode 100644
index 00000000..3ba8ec06
--- /dev/null
+++ b/migrations/2021-04-27-172422-job-candidate-selected-status-migration.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const config = require('config')
+
+/**
+ * Migrate JobCandidate status - from shortlist to selected.
+ */
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.job_candidates`
+ await queryInterface.sequelize.query(`UPDATE ${tableName} SET status = 'selected' WHERE status = 'shortlist'`)
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.job_candidates`
+ await queryInterface.sequelize.query(`UPDATE ${tableName} SET status = 'shortlist' WHERE status = 'selected'`)
+ }
+};
diff --git a/migrations/2021-04-27-172437-job-candidate-rejected-other-status-migration.js b/migrations/2021-04-27-172437-job-candidate-rejected-other-status-migration.js
new file mode 100644
index 00000000..9e8a2480
--- /dev/null
+++ b/migrations/2021-04-27-172437-job-candidate-rejected-other-status-migration.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const config = require('config')
+
+/**
+ * Migrate JobCandidate status - from rejected to rejected - other.
+ */
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.job_candidates`
+ await queryInterface.sequelize.query(
+ `UPDATE ${tableName} SET status = 'rejected - other' WHERE status = 'rejected'`
+ )
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ const tableName = `${config.DB_SCHEMA_NAME}.job_candidates`
+ await queryInterface.sequelize.query(
+ `UPDATE ${tableName} SET status = 'rejected' WHERE status = 'rejected - other'`
+ )
+ }
+};
diff --git a/scripts/recruit-crm-job-import/index.js b/scripts/recruit-crm-job-import/index.js
index c82254ab..596ab680 100644
--- a/scripts/recruit-crm-job-import/index.js
+++ b/scripts/recruit-crm-job-import/index.js
@@ -89,7 +89,7 @@ async function processJob (job, info = []) {
data.resourceBookingId = result.id
}
// update the resourceBooking based on startDate and endDate
- const resourceBookingStatus = dateFNS.isBefore(data.endDate, dateFNS.startOfToday()) ? 'closed' : 'assigned'
+ const resourceBookingStatus = dateFNS.isBefore(data.endDate, dateFNS.startOfToday()) ? 'closed' : 'placed'
logger.debug(`resourceBookingId: ${data.resourceBookingId} status: ${resourceBookingStatus}`)
await helper.updateResourceBookingStatus(data.resourceBookingId, resourceBookingStatus)
info.push({ text: `id: ${data.resourceBookingId} status: ${resourceBookingStatus} resource booking updated`, tag: 'resource_booking_status_updated' })
diff --git a/src/bootstrap.js b/src/bootstrap.js
index 19e93973..6a364e8a 100644
--- a/src/bootstrap.js
+++ b/src/bootstrap.js
@@ -8,15 +8,15 @@ const constants = require('../app-constants')
const config = require('config')
const allowedInterviewStatuses = _.values(Interviews.Status)
-const allowedXAITemplate = _.values(Interviews.XaiTemplate)
+const allowedXAITemplate = _.keys(Interviews.XaiTemplate)
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.resourceBookingStatus = () => Joi.string().valid('placed', 'closed', 'cancelled')
Joi.workload = () => Joi.string().valid('full-time', 'fractional')
-Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview', 'topcoder-rejected')
+Joi.jobCandidateStatus = () => Joi.string().valid('open', 'placed', 'selected', 'client rejected - screening', 'client rejected - interview', 'rejected - other', 'cancelled', 'interview', 'topcoder-rejected')
Joi.title = () => Joi.string().max(128)
Joi.paymentStatus = () => Joi.string().valid('pending', 'partially-completed', 'completed', 'cancelled')
Joi.xaiTemplate = () => Joi.string().valid(...allowedXAITemplate)
diff --git a/src/common/helper.js b/src/common/helper.js
index b65f6ba7..ec55e2d8 100644
--- a/src/common/helper.js
+++ b/src/common/helper.js
@@ -679,6 +679,11 @@ function encodeQueryString (queryObj, nesting = '') {
* @returns {Array} the users found
*/
async function listUsersByExternalId (externalId) {
+ // return empty list if externalId is null or undefined
+ if (!!externalId !== true) {
+ return []
+ }
+
const token = await getM2MUbahnToken()
const q = {
enrich: true,
diff --git a/src/eventHandlers/InterviewEventHandler.js b/src/eventHandlers/InterviewEventHandler.js
index ee503ee5..af7ce400 100644
--- a/src/eventHandlers/InterviewEventHandler.js
+++ b/src/eventHandlers/InterviewEventHandler.js
@@ -3,8 +3,9 @@
*/
const models = require('../models')
-const logger = require('../common/logger')
+// const logger = require('../common/logger')
const helper = require('../common/helper')
+const { Interviews } = require('../../app-constants')
const teamService = require('../services/TeamService')
/**
@@ -15,27 +16,45 @@ const teamService = require('../services/TeamService')
*/
async function sendInvitationEmail (payload) {
const interview = payload.value
+
// get job candidate user details
const jobCandidate = await models.JobCandidate.findById(interview.jobCandidateId)
const jobCandidateUser = await helper.getUserById(jobCandidate.userId, true)
- const jobCandidateUserEmail = helper.getUserAttributeValue(jobCandidateUser, 'email')
+ // const jobCandidateUserEmail = helper.getUserAttributeValue(jobCandidateUser, 'email')
// get customer details
const job = await jobCandidate.getJob()
- const customerUser = await helper.getUserByExternalId(job.externalId, true)
- const customerUserEmail = helper.getUserAttributeValue(customerUser, 'email')
- if (jobCandidateUserEmail && customerUserEmail) {
- teamService.sendEmail({}, {
- template: 'interview-invitation',
- recipients: [jobCandidateUserEmail, customerUserEmail],
- cc: interview.attendeesList,
- data: {
- interviewType: interview.xaiTemplate,
- jobName: job.title,
- candidateName: `${jobCandidateUser.firstName} ${jobCandidateUser.lastName}`,
- customMessage: interview.customMessage
- }
- })
- } else {
+ // const customerUser = await helper.getUserByExternalId(job.externalId, true)
+ // const customerUserEmail = helper.getUserAttributeValue(customerUser, 'email')
+
+ // TODO: remove mock addresses & switch back to the old implementation once API gets fixed
+ // Both emails will be undefined since TC API doesn't return attributes,
+ // this is a workaround to skip check/condition & log the payload
+ // it will post the event nevertheless (with mocked candidate&customer address), so you can see on the logs as kafka event
+ // and verify the payload content
+ const customerMockEmail = 'testcustomer@yopmail.com'
+ const candidateMockEmail = 'testuserforemail@yopmail.com'
+
+ // if (jobCandidateUserEmail && customerUserEmail) {
+ const interviewerList = interview.attendeesList
+ // ? [customerUserEmail, ...interview.attendeesList].join(', ') // "customer@mail.com, first@attendee.com, second@attendee.com..."
+ // : customerUserEmail
+ ? [customerMockEmail, ...interview.attendeesList].join(', ') // "customer@mail.com, first@attendee.com, second@attendee.com..."
+ : customerMockEmail
+ teamService.sendEmail({}, {
+ template: 'interview-invitation',
+ recipients: [candidateMockEmail, customerMockEmail],
+ cc: interview.attendeesList,
+ data: {
+ interviewType: interview.xaiTemplate,
+ interviewRound: interview.round,
+ interviewDuration: Interviews.XaiTemplate[interview.xaiTemplate],
+ interviewerList,
+ jobName: job.title,
+ candidateName: `${jobCandidateUser.firstName} ${jobCandidateUser.lastName}`,
+ candidateId: interview.jobCandidateId
+ }
+ })
+ /* } else {
// one (or both) of the emails are missing due to some reason
// for e.g. some users' externalIds may be set to null or similar
// log error
@@ -44,7 +63,7 @@ async function sendInvitationEmail (payload) {
context: 'sendInvitationEmail',
message: 'Couldn\'t sent invitation emails. Insufficient details.'
})
- }
+ } */
}
/**
diff --git a/src/eventHandlers/ResourceBookingEventHandler.js b/src/eventHandlers/ResourceBookingEventHandler.js
index 95947436..7bf821df 100644
--- a/src/eventHandlers/ResourceBookingEventHandler.js
+++ b/src/eventHandlers/ResourceBookingEventHandler.js
@@ -13,26 +13,26 @@ const WorkPeriodService = require('../services/WorkPeriodService')
const WorkPeriod = models.WorkPeriod
/**
- * When ResourceBooking's status is changed to `assigned`
+ * When ResourceBooking's status is changed to `placed`
* the corresponding JobCandidate record (with the same userId and jobId)
- * should be updated with status `selected`
+ * should be updated with status `placed`
*
* @param {Object} payload the event payload
* @returns {undefined}
*/
-async function selectJobCandidate (payload) {
+async function placeJobCandidate (payload) {
if (_.get(payload, 'options.oldValue') && payload.value.status === payload.options.oldValue.status) {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'selectJobCandidate',
+ context: 'placeJobCandidate',
message: 'status not changed'
})
return
}
- if (payload.value.status !== 'assigned') {
+ if (payload.value.status !== 'placed') {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'selectJobCandidate',
+ context: 'placeJobCandidate',
message: `not interested resource booking - status: ${payload.value.status}`
})
return
@@ -41,7 +41,7 @@ async function selectJobCandidate (payload) {
if (!resourceBooking.jobId) {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'selectJobCandidate',
+ context: 'placeJobCandidate',
message: `id: ${resourceBooking.id} resource booking without jobId - ignored`
})
return
@@ -51,42 +51,42 @@ async function selectJobCandidate (payload) {
jobId: resourceBooking.jobId,
userId: resourceBooking.userId,
status: {
- [Op.not]: 'selected'
+ [Op.not]: 'placed'
}
}
})
await Promise.all(candidates.map(candidate => JobCandidateService.partiallyUpdateJobCandidate(
helper.getAuditM2Muser(),
candidate.id,
- { status: 'selected' }
+ { status: 'placed' }
).then(result => {
logger.info({
component: 'ResourceBookingEventHandler',
- context: 'selectJobCandidate',
+ context: 'placeJobCandidate',
message: `id: ${result.id} candidate got selected.`
})
})))
}
/**
- * Update the status of the Job to assigned when it positions requirement is fullfilled.
+ * Update the status of the Job to placed when it positions requirement is fullfilled.
*
* @param {Object} payload the event payload
* @returns {undefined}
*/
-async function assignJob (payload) {
+async function placeJob (payload) {
if (_.get(payload, 'options.oldValue') && payload.value.status === payload.options.oldValue.status) {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'assignJob',
+ context: 'placeJob',
message: 'status not changed'
})
return
}
- if (payload.value.status !== 'assigned') {
+ if (payload.value.status !== 'placed') {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'assignJob',
+ context: 'placeJob',
message: `not interested resource booking - status: ${payload.value.status}`
})
return
@@ -95,34 +95,34 @@ async function assignJob (payload) {
if (!resourceBooking.jobId) {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'assignJob',
+ context: 'placeJob',
message: `id: ${resourceBooking.id} resource booking without jobId - ignored`
})
return
}
const job = await models.Job.findById(resourceBooking.jobId)
- if (job.status === 'assigned') {
+ if (job.status === 'placed') {
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'assignJob',
- message: `job with projectId ${job.projectId} is already assigned`
+ context: 'placeJob',
+ message: `job with projectId ${job.projectId} is already placed`
})
return
}
const resourceBookings = await models.ResourceBooking.findAll({
where: {
jobId: job.id,
- status: 'assigned'
+ status: 'placed'
}
})
logger.debug({
component: 'ResourceBookingEventHandler',
- context: 'assignJob',
- message: `the number of assigned resource bookings is ${resourceBookings.length} - the numPositions of the job is ${job.numPositions}`
+ context: 'placeJob',
+ message: `the number of placed resource bookings is ${resourceBookings.length} - the numPositions of the job is ${job.numPositions}`
})
if (job.numPositions === resourceBookings.length) {
- await JobService.partiallyUpdateJob(helper.getAuditM2Muser(), job.id, { status: 'assigned' })
- logger.info({ component: 'ResourceBookingEventHandler', context: 'assignJob', message: `job ${job.id} is assigned` })
+ await JobService.partiallyUpdateJob(helper.getAuditM2Muser(), job.id, { status: 'placed' })
+ logger.info({ component: 'ResourceBookingEventHandler', context: 'placeJob', message: `job ${job.id} is placed` })
}
}
@@ -294,8 +294,8 @@ async function _deleteWorkPeriods (workPeriods) {
* @returns {undefined}
*/
async function processCreate (payload) {
- await selectJobCandidate(payload)
- await assignJob(payload)
+ await placeJobCandidate(payload)
+ await placeJob(payload)
await createWorkPeriods(payload)
}
@@ -306,8 +306,8 @@ async function processCreate (payload) {
* @returns {undefined}
*/
async function processUpdate (payload) {
- await selectJobCandidate(payload)
- await assignJob(payload)
+ await placeJobCandidate(payload)
+ await placeJob(payload)
await updateWorkPeriods(payload)
}
diff --git a/src/services/InterviewService.js b/src/services/InterviewService.js
index 2afad72e..d4f67576 100644
--- a/src/services/InterviewService.js
+++ b/src/services/InterviewService.js
@@ -125,10 +125,18 @@ async function requestInterview (currentUser, jobCandidateId, interview) {
})
interview.round = round + 1
- // create
try {
+ // create the interview
const created = await Interview.create(interview)
await helper.postEvent(config.TAAS_INTERVIEW_REQUEST_TOPIC, created.toJSON())
+ // update jobCandidate.status to Interview
+ const [, affectedRows] = await models.JobCandidate.update(
+ { status: 'interview' },
+ { where: { id: created.jobCandidateId }, returning: true }
+ )
+ const updatedJobCandidate = _.omit(_.get(affectedRows, '0.dataValues'), 'deletedAt')
+ await helper.postEvent(config.TAAS_JOB_CANDIDATE_UPDATE_TOPIC, updatedJobCandidate)
+ // return created interview
return created.dataValues
} catch (err) {
// gracefully handle if one of the common sequelize errors
diff --git a/src/services/PaymentService.js b/src/services/PaymentService.js
index 15c6ee7c..7d714f75 100644
--- a/src/services/PaymentService.js
+++ b/src/services/PaymentService.js
@@ -79,13 +79,13 @@ async function createChallenge (challenge, token) {
pureV5Task: true
},
tags: ['Other'],
- startDate: new Date(),
+ startDate: new Date()
}
if (challenge.billingAccountId) {
body.billing = {
billingAccountId: challenge.billingAccountId,
- markup: 0, // for TaaS payments we always use 0 markup
+ markup: 0 // for TaaS payments we always use 0 markup
}
}
try {
diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js
index 4fef4e46..3693f22c 100644
--- a/src/services/ResourceBookingService.js
+++ b/src/services/ResourceBookingService.js
@@ -159,7 +159,7 @@ async function createResourceBooking (currentUser, resourceBooking) {
createResourceBooking.schema = Joi.object().keys({
currentUser: Joi.object().required(),
resourceBooking: Joi.object().keys({
- status: Joi.resourceBookingStatus().default('assigned'),
+ status: Joi.resourceBookingStatus().default('placed'),
projectId: Joi.number().integer().required(),
userId: Joi.string().uuid().required(),
jobId: Joi.string().uuid().allow(null),
diff --git a/src/services/TeamService.js b/src/services/TeamService.js
index 459e6228..8eb6714c 100644
--- a/src/services/TeamService.js
+++ b/src/services/TeamService.js
@@ -23,13 +23,13 @@ const emailTemplates = _.mapValues(emailTemplateConfig, (template) => {
})
/**
- * Function to get assigned resource bookings with specific projectIds
+ * Function to get placed resource bookings with specific projectIds
* @param {Object} currentUser the user who perform this operation.
* @param {Array} projectIds project ids
* @returns the request result
*/
-async function _getAssignedResourceBookingsByProjectIds (currentUser, projectIds) {
- const criteria = { status: 'assigned', projectIds }
+async function _getPlacedResourceBookingsByProjectIds (currentUser, projectIds) {
+ const criteria = { status: 'placed', projectIds }
const { result } = await ResourceBookingService.searchResourceBookings(currentUser, criteria, { returnAll: true })
return result
}
@@ -95,8 +95,8 @@ searchTeams.schema = Joi.object().keys({
*/
async function getTeamDetail (currentUser, projects, isSearch = true) {
const projectIds = _.map(projects, 'id')
- // Get all assigned resourceBookings filtered by projectIds
- const resourceBookings = await _getAssignedResourceBookingsByProjectIds(currentUser, projectIds)
+ // Get all placed resourceBookings filtered by projectIds
+ const resourceBookings = await _getPlacedResourceBookingsByProjectIds(currentUser, projectIds)
// Get all jobs filtered by projectIds
const jobs = await _getJobsByProjectIds(currentUser, projectIds)
@@ -285,7 +285,7 @@ async function getTeamJob (currentUser, id, jobId) {
const photoURLMap = _.groupBy(members, 'handleLower')
result.candidates = _.map(job.candidates, candidate => {
- const candidateData = _.pick(candidate, ['status', 'resume', 'userId', 'id'])
+ const candidateData = _.pick(candidate, ['status', 'resume', 'userId', 'interviews', 'id'])
const userData = userMap[candidate.userId][0]
// attach user data to the candidate
Object.assign(candidateData, _.pick(userData, ['handle', 'firstName', 'lastName', 'skills']))