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/README.md b/README.md index dc66b0dd..0aba9cf3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ # Topcoder TaaS API -## Requirements +## Tech Stack + +- [Node.js](https://nodejs.org/) v12 +- [PostgreSQL](https://www.postgresql.org/) +- [ElasticSearch](https://www.elastic.co/) v7.7 +- [Apache Kafka](https://kafka.apache.org/) + +## Local Setup + +### Requirements - [Node.js](https://nodejs.org/en/) v12+ - [Docker](https://www.docker.com/) @@ -67,15 +76,29 @@ - after that, `taas-es-processor` would be started itself. Make sure it successfully connected to Kafka, you should see 9 lines with text `Subscribed to taas.`: ``` - tc-taas-es-processor | 2021-01-22T14:27:48.971Z DEBUG no-kafka-client Subscribed to taas.jobcandidate.create:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.972Z DEBUG no-kafka-client Subscribed to taas.job.create:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.972Z DEBUG no-kafka-client Subscribed to taas.resourcebooking.delete:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.973Z DEBUG no-kafka-client Subscribed to taas.jobcandidate.delete:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.974Z DEBUG no-kafka-client Subscribed to taas.jobcandidate.update:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.975Z DEBUG no-kafka-client Subscribed to taas.resourcebooking.create:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.976Z DEBUG no-kafka-client Subscribed to taas.job.delete:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.977Z DEBUG no-kafka-client Subscribed to taas.job.update:0 offset 0 leader kafka:9093 - tc-taas-es-processor | 2021-01-22T14:27:48.978Z DEBUG no-kafka-client Subscribed to taas.resourcebooking.update:0 offset 0 leader kafka:9093 + tc-taas-es-processor | [2021-04-09T21:20:19.035Z] app INFO : Starting kafka consumer + tc-taas-es-processor | 2021-04-09T21:20:21.292Z INFO no-kafka-client Joined group taas-es-processor generationId 1 as no-kafka-client-076538fc-60dd-4ca4-a2b9-520bdf73bc9e + tc-taas-es-processor | 2021-04-09T21:20:21.293Z INFO no-kafka-client Elected as group leader + tc-taas-es-processor | 2021-04-09T21:20:21.452Z DEBUG no-kafka-client Subscribed to taas.jobcandidate.create:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.455Z DEBUG no-kafka-client Subscribed to taas.job.create:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.456Z DEBUG no-kafka-client Subscribed to taas.resourcebooking.delete:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.457Z DEBUG no-kafka-client Subscribed to taas.jobcandidate.delete:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.458Z DEBUG no-kafka-client Subscribed to taas.jobcandidate.update:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.459Z DEBUG no-kafka-client Subscribed to taas.resourcebooking.create:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.461Z DEBUG no-kafka-client Subscribed to taas.job.delete:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.463Z DEBUG no-kafka-client Subscribed to taas.workperiod.update:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.466Z DEBUG no-kafka-client Subscribed to taas.workperiod.delete:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.468Z DEBUG no-kafka-client Subscribed to taas.workperiod.create:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.469Z DEBUG no-kafka-client Subscribed to taas.workperiodpayment.update:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.470Z DEBUG no-kafka-client Subscribed to taas.workperiodpayment.delete:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.471Z DEBUG no-kafka-client Subscribed to taas.workperiodpayment.create:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.473Z DEBUG no-kafka-client Subscribed to taas.job.update:0 offset 0 leader kafka:9093 + tc-taas-es-processor | 2021-04-09T21:20:21.474Z DEBUG no-kafka-client Subscribed to taas.resourcebooking.update:0 offset 0 leader kafka:9093 + tc-taas-es-processor | [2021-04-09T21:20:21.475Z] app INFO : Initialized....... + tc-taas-es-processor | [2021-04-09T21:20:21.479Z] app INFO : taas.job.create,taas.job.update,taas.job.delete,taas.jobcandidate.create,taas.jobcandidate.update,taas.jobcandidate.delete,taas.resourcebooking.create,taas.resourcebooking.update,taas.resourcebooking.delete,taas.workperiod.create,taas.workperiod.update,taas.workperiod.delete,taas.workperiodpayment.create,taas.workperiodpayment.update,taas.workperiodpayment.delete + tc-taas-es-processor | [2021-04-09T21:20:21.480Z] app INFO : Kick Start....... + tc-taas-es-processor | ********** Topcoder Health Check DropIn listening on port 3001 + tc-taas-es-processor | Topcoder Health Check DropIn started and ready to roll ``` @@ -86,14 +109,14 @@
This docker-compose file starts the next services: - | Service | Name | Port | - |----------|:-----:|:----:| - | PostgreSQL | postgres | 5432 | - | Elasticsearch | elasticsearch | 9200 | - | Zookeeper | zookeeper | 2181 | - | Kafka | kafka | 9092 | - | [tc-bus-api](https://github.com/topcoder-platform/tc-bus-api) | tc-bus-api | 8002 | - | [taas-es-processor](https://github.com/topcoder-platform/taas-es-processor) | taas-es-processor | 5000 | + | Service | Name | Port | + | --------------------------------------------------------------------------- | :---------------: | :---: | + | PostgreSQL | postgres | 5432 | + | Elasticsearch | elasticsearch | 9200 | + | Zookeeper | zookeeper | 2181 | + | Kafka | kafka | 9092 | + | [tc-bus-api](https://github.com/topcoder-platform/tc-bus-api) | tc-bus-api | 8002 | + | [taas-es-processor](https://github.com/topcoder-platform/taas-es-processor) | taas-es-processor | 5000 | - as many of the Topcoder services in this docker-compose require Auth0 configuration for M2M calls, our docker-compose file passes environment variables `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_URL`, `AUTH0_AUDIENCE`, `AUTH0_PROXY_SERVER_URL` to its containers. docker-compose takes them from `.env` file if provided. @@ -105,7 +128,7 @@ npm run services:log -- -f SERVICE_NAME ``` - - If you want to modify the code of any of the services which are run inside this docker-compose file, you can stop such service inside docker-compose by command `docker-compose -f local/docker-compose.yml stop -f ` and run the service separately, following its README file. + - If you want to modify the code of any of the services which are run inside this docker-compose file, you can stop such service inside docker-compose by command `docker-compose -f local/docker-compose.yml stop ` and run the service separately, following its README file. @@ -134,31 +157,68 @@ ## NPM Commands -| Command                    | Description | -| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| `npm run lint` | Check for for lint errors. | -| `npm run lint:fix` | Check for for lint errors and fix error automatically when possible. | -| `npm run build` | Build source code for production run into `dist` folder. | -| `npm run start` | Start app in the production mode from prebuilt `dist` folder. | -| `npm run dev` | Start app in the development mode using `nodemon`. | -| `npm run test` | Run tests. | -| `npm run init-db` | Initializes Database. | -| `npm run create-index` | Create Elasticsearch indexes. Use `-- --force` flag to skip confirmation | -| `npm run delete-index` | Delete Elasticsearch indexes. Use `-- --force` flag to skip confirmation | -| `npm run data:import ` | Imports data into ES and db from filePath (`./data/demo-data.json` is used as default). Use `-- --force` flag to skip confirmation | -| `npm run data:export ` | Exports data from ES and db into filePath (`./data/demo-data.json` is used as default). Use `-- --force` flag to skip confirmation | -| `npm run index:all` | Indexes all data from db into ES. Use `-- --force` flag to skip confirmation| -| `npm run index:jobs ` | Indexes job data from db into ES, if jobId is not given all data is indexed. Use `-- --force` flag to skip confirmation | -| `npm run index:job-candidates ` | Indexes job candidate data from db into ES, if jobCandidateId is not given all data is indexed. Use `-- --force` flag to skip confirmation | -| `npm run index:resource-bookings ` | Indexes resource bookings data from db into ES, if resourceBookingsId is not given all data is indexed. Use `-- --force` flag to skip confirmation | -| `npm run services:up` | Start services via docker-compose for local development. | -| `npm run services:down` | Stop services via docker-compose for local development. | -| `npm run services:logs -- -f ` | View logs of some service inside docker-compose. | -| `npm run local:init` | Recreate Database and Elasticsearch indexes and populate demo data for local development (removes any existent data). | -| `npm run local:reset` | Recreate Database and Elasticsearch indexes (removes any existent data). | -| `npm run cov` | Code Coverage Report. | -| `npm run migrate` | Run any migration files which haven't run yet. | -| `npm run migrate:undo` | Revert most recent migration. | +| Command                    | Description | +| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `npm run lint` | Check for for lint errors. | +| `npm run lint:fix` | Check for for lint errors and fix error automatically when possible. | +| `npm run build` | Build source code for production run into `dist` folder. | +| `npm run start` | Start app in the production mode from prebuilt `dist` folder. | +| `npm run dev` | Start app in the development mode using `nodemon`. | +| `npm run test` | Run tests. | +| `npm run init-db` | Initializes Database. | +| `npm run create-index` | Create Elasticsearch indexes. Use `-- --force` flag to skip confirmation | +| `npm run delete-index` | Delete Elasticsearch indexes. Use `-- --force` flag to skip confirmation | +| `npm run data:import ` | Imports data into ES and db from filePath (`./data/demo-data.json` is used as default). Use `-- --force` flag to skip confirmation | +| `npm run data:export ` | Exports data from ES and db into filePath (`./data/demo-data.json` is used as default). Use `-- --force` flag to skip confirmation | +| `npm run index:all` | Indexes all data from db into ES. Use `-- --force` flag to skip confirmation | +| `npm run index:jobs ` | Indexes job data from db into ES, if jobId is not given all data is indexed. Use `-- --force` flag to skip confirmation | +| `npm run index:job-candidates ` | Indexes job candidate data from db into ES, if jobCandidateId is not given all data is indexed. Use `-- --force` flag to skip confirmation | +| `npm run index:resource-bookings ` | Indexes resource bookings data from db into ES, if resourceBookingsId is not given all data is indexed. Use `-- --force` flag to skip confirmation | +| `npm run index:work-periods ` | Indexes work periods data from db into ES, if workPeriodId is not given all data is indexed. Use `-- --force` flag to skip confirmation | +| `npm run services:up` | Start services via docker-compose for local development. | +| `npm run services:down` | Stop services via docker-compose for local development. | +| `npm run services:logs -- -f ` | View logs of some service inside docker-compose. | +| `npm run local:init` | Recreate Database and Elasticsearch indexes and populate demo data for local development (removes any existent data). | +| `npm run local:reset` | Recreate Database and Elasticsearch indexes (removes any existent data). | +| `npm run cov` | Code Coverage Report. | +| `npm run migrate` | Run any migration files which haven't run yet. | +| `npm run migrate:undo` | Revert most recent migration. | + +## Import and Export data + +### 📤 Export data + +To export data to the default file `data/demo-data.json`, run: +```bash +npm run data:export +``` + +If you want to export data to another file, run: + +```bash +npm run data:export -- --file path/to-file.json +``` + +- List of models that will be exported are defined in `scripts/data/exportData.js`. + +### 📥 Import data + +⚠️ This command would clear any existent data in DB and ES before importing. + +*During importing, data would be first imported to the database, and after from the database it would be indexed to the Elasticsearch index.* + +To import data from the default file `data/demo-data.json`, run: +```bash +npm run data:import +``` + +If you want to import data from another file, run: + +```bash +npm run data:import -- --file path/to-file.json +``` + +- List of models that will be imported are defined in `scripts/data/importData.js`. ## Kafka commands @@ -209,3 +269,30 @@ The following parameters can be set in the config file or via env variables: - Run `npm run test` to execute unit tests - Run `npm run cov` to execute unit tests and generate coverage report. + +## 📋 Code Guidelines + +### General Requirements + +- Split code into reusable methods where applicable. +- Lint should pass. +- Unit tests should pass. + +### Documentation and Utils + +When we add, update or delete models and/or endpoints we have to make sure that we keep documentation and utility scripts up to date. + +- **Swagger** +- **Postman** +- **ES Mapping** + - Update mapping definitions for ElasticSearch indexes inside both repositories [taas-apis](https://github.com/topcoder-platform/taas-apis) and [taas-es-processor](https://github.com/topcoder-platform/taas-es-processor). +- **Reindex** + - NPM command `index:all` should re-index data in all ES indexes. + - There should be an individual NPM command `index:*` which would re-index data only in one ES index. +- **Import/Export** + - NPM commands `data:import` and `data:export` should support importing/exporting data from/to all the models. +- **Create/Delete Index** + - NPM commands `create-index` and `delete-index` should support creating/deleting all the indexes. +- **DB Migration** + - If there are any updates in DB schemas, create a DB migration script inside `migrations` folder which would make any necessary updates to the DB schema. + - Test, that when we migrate DB from the previous state using `npm run migrate`, we get exactly the same DB schema as if we create DB from scratch using command `npm run init-db force`. diff --git a/app-constants.js b/app-constants.js index e9747f85..7ee4c5f5 100644 --- a/app-constants.js +++ b/app-constants.js @@ -33,11 +33,35 @@ const Scopes = { DELETE_RESOURCE_BOOKING: 'delete:taas-resourceBookings', ALL_RESOURCE_BOOKING: 'all:taas-resourceBookings', // taas-team - READ_TAAS_TEAM: 'read:taas-teams' + READ_TAAS_TEAM: 'read:taas-teams', + // work period + READ_WORK_PERIOD: 'read:taas-workPeriods', + CREATE_WORK_PERIOD: 'create:taas-workPeriods', + UPDATE_WORK_PERIOD: 'update:taas-workPeriods', + DELETE_WORK_PERIOD: 'delete:taas-workPeriods', + ALL_WORK_PERIOD: 'all:taas-workPeriods', + // work period payment + READ_WORK_PERIOD_PAYMENT: 'read:taas-workPeriodPayments', + CREATE_WORK_PERIOD_PAYMENT: 'create:taas-workPeriodPayments', + UPDATE_WORK_PERIOD_PAYMENT: 'update:taas-workPeriodPayments', + ALL_WORK_PERIOD_PAYMENT: 'all:taas-workPeriodPayments' +} + +const ChallengeStatus = { + DRAFT: 'Draft', + ACTIVE: 'Active', + COMPLETED: 'Completed' +} + +const PaymentProcessingSwitch = { + ON: 'ON', + OFF: 'OFF' } module.exports = { UserRoles, FullManagePermissionRoles, - Scopes + Scopes, + ChallengeStatus, + PaymentProcessingSwitch } diff --git a/config/default.js b/config/default.js index e475a677..d959ba07 100644 --- a/config/default.js +++ b/config/default.js @@ -76,6 +76,8 @@ module.exports = { ES_INDEX_JOB_CANDIDATE: process.env.ES_INDEX_JOB_CANDIDATE || 'job_candidate', // the resource booking index ES_INDEX_RESOURCE_BOOKING: process.env.ES_INDEX_RESOURCE_BOOKING || 'resource_booking', + // the work period index + ES_INDEX_WORK_PERIOD: process.env.ES_INDEX_WORK_PERIOD || 'work_period', // the max bulk size in MB for ES indexing MAX_BULK_REQUEST_SIZE_MB: process.env.MAX_BULK_REQUEST_SIZE_MB || 20, @@ -103,13 +105,27 @@ module.exports = { TAAS_JOB_CANDIDATE_UPDATE_TOPIC: process.env.TAAS_JOB_CANDIDATE_UPDATE_TOPIC || 'taas.jobcandidate.update', // the delete job candidate entity Kafka message topic TAAS_JOB_CANDIDATE_DELETE_TOPIC: process.env.TAAS_JOB_CANDIDATE_DELETE_TOPIC || 'taas.jobcandidate.delete', - // topics for job service + // topics for resource booking service // the create resource booking entity Kafka message topic TAAS_RESOURCE_BOOKING_CREATE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_CREATE_TOPIC || 'taas.resourcebooking.create', // the update resource booking entity Kafka message topic TAAS_RESOURCE_BOOKING_UPDATE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC || 'taas.resourcebooking.update', // 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 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', + // the delete work period entity Kafka message topic + TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete', + // topics for work period payment service + // the create work period payment entity Kafka message topic + TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC || 'taas.workperiodpayment.create', + // the update work period payment entity Kafka message topic + TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC || 'taas.workperiodpayment.update', + // the delete work period payment entity Kafka message topic + TAAS_WORK_PERIOD_PAYMENT_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_DELETE_TOPIC || 'taas.workperiodpayment.delete', // the Kafka message topic for sending email EMAIL_TOPIC: process.env.EMAIL_TOPIC || 'external.action.email', @@ -124,5 +140,12 @@ 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', + // environment variables for Payment Service + ROLE_ID_SUBMITTER: process.env.ROLE_ID_SUBMITTER || '732339e7-8e30-49d7-9198-cccf9451e221', + TYPE_ID_TASK: process.env.TYPE_ID_TASK || 'ecd58c69-238f-43a4-a4bb-d172719b9f31', + DEFAULT_TIMELINE_TEMPLATE_ID: process.env.DEFAULT_TIMELINE_TEMPLATE_ID || '53a307ce-b4b3-4d6f-b9a1-3741a58f77e6', + DEFAULT_TRACK_ID: process.env.DEFAULT_TRACK_ID || '9b6fc876-f4d9-4ccb-9dfd-419247628825', + + PAYMENT_PROCESSING_SWITCH: process.env.PAYMENT_PROCESSING_SWITCH || 'OFF' } diff --git a/data/demo-data.json b/data/demo-data.json index 6c8872b4..78bfac23 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","endDate":"2020-09-27T04:17:23.131Z","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","createdAt":"2021-01-28T19:36:33.409Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"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","endDate":"2020-09-27T04:17:23.131Z","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","createdAt":"2021-01-28T19:36:44.975Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:38:17.463Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","endDate":"2020-09-27T04:17:23.131Z","numPositions":7,"resourceType":"Dummy Resource Type","rateType":"weekly","workload":"full-time","skills":[],"status":"assigned","createdAt":"2021-01-28T19:38:23.739Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:10.607Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","endDate":"2020-09-27T04:17:23.131Z","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","createdAt":"2021-01-28T19:41:21.892Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:28.849Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","endDate":"2020-09-27T04:17:23.131Z","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","createdAt":"2021-01-28T19:41:35.098Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:42.124Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"}],"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,"createdAt":"2021-01-28T19:37:05.723Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"7ff45b8f-2b71-4510-b760-8dfa62e79504","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"243517dd-77d7-4f70-8951-0bc66da83076","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:11.598Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"91d63d5f-01d5-419e-89df-6117ea92f535","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"a2e28bf4-1147-41a6-a39f-e2509306f2a6","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:18.066Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"257f98d9-45f7-4e13-a6c2-d7e7b6efc9fe","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"b8649393-d32f-4b7f-a156-12e9776acb0e","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:24.095Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"a01852d0-fa08-410c-b97b-67580ce62215","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"a0a3a5ce-1de6-465d-91b2-518feb299851","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:29.734Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"2fd7ca69-c8ec-4bf3-a7f3-655fbfe3e7df","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"e6958d77-ffaf-4d24-9cdb-6391506695a4","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:44.728Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"f0023058-2996-4bba-8c5f-d09a7023be38","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"626bb327-e738-48e3-8f67-1fa2dc677d3c","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:50.619Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"a189b34d-acde-4633-b18b-f7a34d7c5a74","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"b49a0adb-1565-4de1-9189-a763c77f5ed4","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:37:56.456Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"5191a860-4327-4c50-b76b-84beba04519b","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"79ce2a3e-7679-48cf-8ac9-0a8ca4c4b463","status":"shortlist","externalId":null,"resume":null,"createdAt":"2021-01-28T19:36:51.222Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:38:02.293Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"id":"e6d9635c-b122-4f69-9285-09fb1ab30106","jobId":"a5b3bf94-a8bf-4c7e-b685-70a29a4d7d6e","userId":"98ec2c16-442e-4b61-8ad1-66123ee37d3c","status":"rejected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:36:58.774Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:38:13.553Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"id":"f67b155e-0f09-4fdd-89a7-d79c5e46cac6","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"05e988b7-7d54-4c10-ada1-1a04870a88a8","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:38:38.332Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"8ffd33d3-4a43-4719-aee4-8e46be1d8f1c","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"a2ffdeed-704d-4cf7-b70a-93fcf61de598","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:38:43.967Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"2b8ba549-8878-43d6-ad5f-6a66e3b9d6c9","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"4709473d-f060-4102-87f8-4d51ff0b34c1","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:38:50.106Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"ae5a81ec-5d05-43c4-8253-847d91a54711","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"39c7376e-2d5c-4601-bc47-6b60f505814d","status":"open","externalId":null,"resume":null,"createdAt":"2021-01-28T19:38:55.734Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":null,"updatedBy":null},{"id":"85d6649e-2682-4904-9480-a77b72fef27d","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"213d2dd9-1fc3-4eda-ad97-2d56e2a84a1e","status":"selected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:38:30.856Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:27.209Z","updatedBy":"00000000-0000-0000-0000-000000000000"},{"id":"922dfce3-4e06-4387-9fdb-64f70675e86b","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"dd5adacb-444d-4992-8b7b-0c349be598db","status":"selected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:39:02.435Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:49.349Z","updatedBy":"00000000-0000-0000-0000-000000000000"},{"id":"c26c38e2-a47d-405b-abc6-fe62a739561c","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"6d0509c7-5f12-4d84-9a19-8e80ef7ddd66","status":"selected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:39:08.233Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:53.659Z","updatedBy":"00000000-0000-0000-0000-000000000000"},{"id":"7bef2b37-e1ee-4638-bfc1-c911787ac955","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"f65e2104-2987-4136-839d-ee4632f0b2e5","status":"selected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:39:13.469Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:57.999Z","updatedBy":"00000000-0000-0000-0000-000000000000"},{"id":"e9716139-1f40-4bf1-9f8a-77ae4bcc621e","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"e5e667ad-0950-43c2-8d1d-6e83ad7d1c7e","status":"selected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:39:19.215Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:01.953Z","updatedBy":"00000000-0000-0000-0000-000000000000"},{"id":"a1731d01-eac9-4eff-8e5a-8a3c99bc66e0","jobId":"2d5e2a52-e0dd-4cd9-8f4c-7cffa43951d0","userId":"bef43122-426b-4b2b-acdd-9b5b3bd1c0bf","status":"selected","externalId":null,"resume":null,"createdAt":"2021-01-28T19:39:24.625Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:06.370Z","updatedBy":"00000000-0000-0000-0000-000000000000"}],"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","createdAt":"2021-01-28T19:39:30.052Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:25.260Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:39:35.571Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:30.291Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:39:41.205Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:34.859Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:39:46.515Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:38.820Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:39:52.063Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:43.021Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:39:59.432Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:47.743Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:40:04.761Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:52.303Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:40:09.879Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:40:56.381Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:40:15.326Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:00.503Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"},{"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","createdAt":"2021-01-28T19:40:20.627Z","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-01-28T19:41:04.919Z","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c"}]} \ 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-25","endDate":"2021-01-31","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-25","endDate":"2021-05-31","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-27","endDate":"2021-03-15","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-25","endDate":"2021-04-01","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-18","endDate":"2021-05-28","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-27","endDate":"2000-04-28","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-27","endDate":"2020-05-27","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-25","endDate":"2021-05-01","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-25","endDate":"2021-07-31","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-27","endDate":"2021-09-27","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":"07783b60-b726-41c2-8955-7766a27c1ec5","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":2,"memberRate":4.8,"customerRate":4.95,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"6ed667a5-275e-4f27-984b-34dff5f8a1ff","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-01","endDate":"2021-08-07","daysWorked":5,"memberRate":25.21,"customerRate":10.05,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"d049e7bc-c827-482b-9ec6-b87d9289d1cd","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-24","endDate":"2020-05-30","daysWorked":3,"memberRate":24.46,"customerRate":18.76,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.806Z","updatedAt":null},{"id":"1b633124-f62c-4026-b679-213cf5812689","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":5,"memberRate":23.35,"customerRate":18.76,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"30c89d78-df85-44ed-92b2-b683d8960fc2","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":5,"memberRate":3.96,"customerRate":4.95,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"531754f3-405e-42eb-932a-c1ce7b9386e7","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-02-28","endDate":"2021-03-06","daysWorked":5,"memberRate":3.62,"customerRate":10.05,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.695Z","updatedAt":null},{"id":"442b0543-e887-42be-9ff5-5fee825526be","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":1,"memberRate":23.81,"customerRate":15.49,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.694Z","updatedAt":null},{"id":"18a73600-5ee8-484b-9747-70ea80ce2bd9","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-16","endDate":"2021-05-22","daysWorked":5,"memberRate":28.76,"customerRate":25.9,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"5392acee-b504-4720-95fa-dab585acb607","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":5,"memberRate":14.77,"customerRate":26.72,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.693Z","updatedAt":null},{"id":"1bbc86c8-8c74-4d78-9706-25c4c99721f3","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":5,"memberRate":3.62,"customerRate":25.9,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.695Z","updatedAt":null},{"id":"8b7b49de-29b1-4a0c-bb67-e70cc700fcfd","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-25","endDate":"2021-05-01","daysWorked":5,"memberRate":24.68,"customerRate":23.15,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"b8a8b558-0cb9-46d0-ba9d-2222f3fbdb63","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-05","endDate":"2021-09-11","daysWorked":5,"memberRate":27.42,"customerRate":27.91,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"f70509c0-baed-4ff1-8022-12441251f7af","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":2,"memberRate":30.24,"customerRate":9.88,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"da8abd64-2878-4e09-b3b1-41a27a0576d4","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-12","endDate":"2021-09-18","daysWorked":5,"memberRate":16.86,"customerRate":4.05,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"b5261ee2-bc4d-4c3a-9d30-6703bfdcfbc5","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-23","endDate":"2021-05-29","daysWorked":5,"memberRate":24.68,"customerRate":27.91,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"829165cb-0150-48e7-995c-f5b4d1a51d3b","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-26","endDate":"2021-10-02","daysWorked":1,"memberRate":4.8,"customerRate":10.59,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"2430fb35-826a-4e9f-8fb6-8dbcb035d505","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-22","endDate":"2021-08-28","daysWorked":5,"memberRate":6.18,"customerRate":4.05,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"c7ff2acc-a4c2-4e8b-a905-813dd9d1b293","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":4,"memberRate":24.46,"customerRate":4.05,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.695Z","updatedAt":null},{"id":"731db5d7-bb79-45f4-b1b2-9f60d30f7966","resourceBookingId":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","userHandle":"ritesh_cs","projectId":111,"startDate":"2021-01-31","endDate":"2021-02-06","daysWorked":0,"memberRate":27.42,"customerRate":4.4,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.775Z","updatedAt":null},{"id":"b682660e-488e-4033-aaf3-ef37248abc90","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-02-21","endDate":"2021-02-27","daysWorked":0,"memberRate":24.46,"customerRate":2.55,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.693Z","updatedAt":null},{"id":"b4566e24-4fa8-4e82-9950-f62134bb00df","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-29","endDate":"2021-09-04","daysWorked":5,"memberRate":4.8,"customerRate":4.4,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"584c931b-da72-416e-a011-eac5fe34f42f","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-07-25","endDate":"2021-07-31","daysWorked":4,"memberRate":14.77,"customerRate":4.4,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"703bc625-9144-4a9f-a91b-445e171d8ea9","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-09-19","endDate":"2021-09-25","daysWorked":5,"memberRate":27.42,"customerRate":5.77,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"c9685cb2-9f4a-497e-ae99-deed7b16cc34","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-07","endDate":"2021-03-13","daysWorked":5,"memberRate":14.77,"customerRate":16.55,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.695Z","updatedAt":null},{"id":"428fec88-b305-4816-b5ef-be2b4e91c21a","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-04","endDate":"2021-04-10","daysWorked":5,"memberRate":8.55,"customerRate":16.55,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"374e2065-40cb-4651-a55c-81a0675dc00d","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-17","endDate":"2020-05-23","daysWorked":5,"memberRate":16.86,"customerRate":1.89,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.806Z","updatedAt":null},{"id":"4bfdc253-e39a-4cfa-9a45-2cfc6e93cc6f","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-16","endDate":"2000-04-22","daysWorked":5,"memberRate":20.16,"customerRate":13.92,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.858Z","updatedAt":null},{"id":"0ba1a0b3-7bee-4fe6-9083-d36d8ca9d052","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-03-14","endDate":"2021-03-20","daysWorked":5,"memberRate":24.46,"customerRate":1.44,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.695Z","updatedAt":null},{"id":"6da7d347-7492-43b1-a49d-8a6e1daf9b22","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-18","endDate":"2021-04-24","daysWorked":5,"memberRate":25.21,"customerRate":1.44,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"8c8cedf3-0bb6-4063-8a3a-faf1626da384","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-09","endDate":"2000-04-15","daysWorked":5,"memberRate":14.77,"customerRate":4.95,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.858Z","updatedAt":null},{"id":"10394696-47f4-4761-8d14-ffdf012cde23","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-25","endDate":"2021-07-31","daysWorked":5,"memberRate":3.62,"customerRate":4.95,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"64de2244-6fcf-45ac-8a89-a9b3420e4476","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-18","endDate":"2021-04-24","daysWorked":5,"memberRate":22.57,"customerRate":18.23,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"2cbe3836-5961-4d58-b8f7-44b84ddf3fc5","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":5,"memberRate":25.21,"customerRate":2.64,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"bc8611f0-4ac2-49b2-b776-59ed2b759d1d","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-04","endDate":"2021-07-10","daysWorked":5,"memberRate":16.86,"customerRate":5.77,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"9b6fc85b-3694-4e6c-9ebf-fe9ccf7881ba","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-13","endDate":"2021-06-19","daysWorked":5,"memberRate":14.77,"customerRate":15.86,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"4a2c581f-c626-44cb-8ada-58f0172e8b4d","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-05-30","endDate":"2021-06-05","daysWorked":5,"memberRate":28.76,"customerRate":15.49,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"90d99323-ba57-4a18-b50f-78f387033c70","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-02","endDate":"2000-04-08","daysWorked":5,"memberRate":24.46,"customerRate":25.9,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.858Z","updatedAt":null},{"id":"5ddc132b-3205-45e3-bfe9-f1a4f939885e","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-03-21","endDate":"2021-03-27","daysWorked":5,"memberRate":21.53,"customerRate":25.9,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"437d4281-43ec-4de3-85e4-51d298388ce5","resourceBookingId":"0a6799d7-f5d1-456b-8bf1-90619284b295","userHandle":"aaaa","projectId":111,"startDate":"2021-02-28","endDate":"2021-03-06","daysWorked":5,"memberRate":26.19,"customerRate":28.03,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.693Z","updatedAt":null},{"id":"a35bb205-361b-4b2d-9828-55501ae9d190","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-11","endDate":"2021-07-17","daysWorked":5,"memberRate":27.42,"customerRate":28.03,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"40ae1e8f-24be-4b51-885c-51f08e15f0df","resourceBookingId":"08f5e4b9-1088-496d-91a7-5b22a3583e3c","userHandle":"ritesh_cs","projectId":111,"startDate":"2021-01-24","endDate":"2021-01-30","daysWorked":5,"memberRate":16.86,"customerRate":28.03,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.775Z","updatedAt":null},{"id":"e19bddc5-38ac-43c9-8273-bc9069de26b3","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-04-23","endDate":"2000-04-29","daysWorked":5,"memberRate":6.18,"customerRate":9.12,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.858Z","updatedAt":null},{"id":"bf61dad8-841a-4913-93f6-b2ae516b8b11","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-06","endDate":"2021-06-12","daysWorked":5,"memberRate":6.18,"customerRate":4.4,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"93b0f03b-219b-41d5-bb1e-f125651b1b0e","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-03","endDate":"2020-05-09","daysWorked":5,"memberRate":24.46,"customerRate":1.89,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.806Z","updatedAt":null},{"id":"93e69f99-cb1c-418e-aa41-ab2181b4bcfd","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-27","endDate":"2021-07-03","daysWorked":5,"memberRate":17.2,"customerRate":13.92,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"619a0835-730f-47ec-820e-3959821aec51","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-30","endDate":"2021-06-05","daysWorked":1,"memberRate":4.8,"customerRate":13.92,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"558b4685-4932-492e-99e1-2830c10f8275","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-04-25","endDate":"2021-05-01","daysWorked":5,"memberRate":4.8,"customerRate":13.92,"paymentStatus":"pending","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"84431dac-019d-4987-9817-15f5f000d2db","resourceBookingId":"61f5d474-e41f-490b-ab58-9f983e3d4916","userHandle":"sonu628","projectId":111,"startDate":"2000-03-26","endDate":"2000-04-01","daysWorked":5,"memberRate":27.42,"customerRate":4.05,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.858Z","updatedAt":null},{"id":"f575df2d-f170-4251-9042-b17ca5e99ca5","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-02","endDate":"2021-05-08","daysWorked":5,"memberRate":4.82,"customerRate":4.05,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"3829c216-ef3f-466c-93da-3a88a961442f","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-09","endDate":"2021-05-15","daysWorked":5,"memberRate":6.18,"customerRate":4.4,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"bd54bcaf-5278-467f-a166-865048774d0e","resourceBookingId":"a098e8d8-ce5b-47d9-afee-38b050d16745","userHandle":"TCConnCopilot","projectId":111,"startDate":"2021-04-25","endDate":"2021-05-01","daysWorked":5,"memberRate":16.86,"customerRate":1.89,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.696Z","updatedAt":null},{"id":"7f8f3a25-b1d2-4e36-a543-fcaae57a32f5","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-15","endDate":"2021-08-21","daysWorked":5,"memberRate":8.13,"customerRate":1.89,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"6e1dc024-d437-4d9f-92e9-561db713a19a","resourceBookingId":"dc4477ec-07f8-4c8e-a8fe-ffe38dd290fa","userHandle":"nskumar278","projectId":111,"startDate":"2021-08-08","endDate":"2021-08-14","daysWorked":5,"memberRate":3.62,"customerRate":18.14,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.703Z","updatedAt":null},{"id":"c5f6ae8f-2976-46d1-bd66-58eeb58ca045","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-06-20","endDate":"2021-06-26","daysWorked":5,"memberRate":25.41,"customerRate":13.92,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"0f480aa7-1c5d-42fe-aad6-c774e58c2e17","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-09","endDate":"2021-05-15","daysWorked":5,"memberRate":4.82,"customerRate":4.95,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"098ca553-6ea4-4cae-a18e-762f47e93d82","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-05-16","endDate":"2021-05-22","daysWorked":5,"memberRate":3.96,"customerRate":4.95,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"729a2396-2b33-4185-8ce8-d929dbf4a472","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-23","endDate":"2021-05-29","daysWorked":5,"memberRate":17.2,"customerRate":4.95,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"9bfbd49a-e6bb-45c3-965d-ed4f95f0878a","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-07-18","endDate":"2021-07-24","daysWorked":5,"memberRate":23.35,"customerRate":5.77,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"dcc310cf-ea4a-4637-9bf5-5baaabea67b3","resourceBookingId":"d38a6223-3f91-4300-9ecb-6e5fee173625","userHandle":"nithyaasworld","projectId":111,"startDate":"2021-05-23","endDate":"2021-05-29","daysWorked":4,"memberRate":14.77,"customerRate":1.44,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.706Z","updatedAt":null},{"id":"309f65e8-b0b5-4cbb-ba60-9b36ccba4bd5","resourceBookingId":"51b45f5d-5df2-46d5-9c3d-8a1323df38dd","userHandle":"amy_admin","projectId":111,"startDate":"2021-04-11","endDate":"2021-04-17","daysWorked":5,"memberRate":14.77,"customerRate":15.49,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.704Z","updatedAt":null},{"id":"1e2c732e-ac1f-47ad-939b-22b2078124e5","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-03-28","endDate":"2021-04-03","daysWorked":5,"memberRate":17.2,"customerRate":15.49,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"2463003f-ee60-4aba-b989-b63babcd9b8b","resourceBookingId":"7d967fed-9792-4768-98a7-0b644aa84f2e","userHandle":"sachin-wipro","projectId":111,"startDate":"2021-05-02","endDate":"2021-05-08","daysWorked":5,"memberRate":4.8,"customerRate":15.49,"paymentStatus":"cancelled","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.705Z","updatedAt":null},{"id":"6a1180b8-38af-4bd0-8a5f-a60626e0bc95","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-04-26","endDate":"2020-05-02","daysWorked":5,"memberRate":26.19,"customerRate":28.03,"paymentStatus":"completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.806Z","updatedAt":null},{"id":"b21f921a-4b23-423d-814b-d31f5cba7f64","resourceBookingId":"35e1abd8-1890-4664-bb52-aade382d7b66","userHandle":"lakshmiaconnmgr","projectId":111,"startDate":"2021-02-21","endDate":"2021-02-27","daysWorked":2,"memberRate":15.77,"customerRate":28.03,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.695Z","updatedAt":null},{"id":"4db82b0b-4d6f-4e9a-b957-ab405b2c2df2","resourceBookingId":"8173579e-4b3c-418d-a9a1-c999caa38404","userHandle":"testcat","projectId":111,"startDate":"2020-05-10","endDate":"2020-05-16","daysWorked":5,"memberRate":24.46,"customerRate":28.03,"paymentStatus":"partially-completed","createdBy":"00000000-0000-0000-0000-000000000000","updatedBy":null,"createdAt":"2021-04-21T20:24:52.806Z","updatedAt":null}],"WorkPeriodPayment":[{"id":"2c488b36-0868-4db6-8978-20b1ce174496","workPeriodId":"07783b60-b726-41c2-8955-7766a27c1ec5","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"d0f61c2d-271c-48b2-8416-50c1c32ad32b","workPeriodId":"098ca553-6ea4-4cae-a18e-762f47e93d82","challengeId":"aa8c1945-904c-42a7-9b00-1e4f9a49dcdb","amount":450,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"90bb43bd-d9e7-4eab-a46b-ab03338be11a","workPeriodId":"0ba1a0b3-7bee-4fe6-9083-d36d8ca9d052","challengeId":"8b6f4040-d7ae-4264-b60b-b1171c9365e4","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"58681a3e-2266-4153-afd5-7be218966da2","workPeriodId":"0f480aa7-1c5d-42fe-aad6-c774e58c2e17","challengeId":"2bafdd9a-ab4a-4624-8a06-7b1adfb8dac2","amount":1200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"b342d615-d36d-48b2-a3e8-1f498b58ab68","workPeriodId":"10394696-47f4-4761-8d14-ffdf012cde23","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-16T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"63cec011-7714-4ab6-944f-e76b9fa2bd1a","workPeriodId":"18a73600-5ee8-484b-9747-70ea80ce2bd9","challengeId":"1bdf092e-e117-4d42-bb5d-e49816171c0d","amount":500,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"8a0c0877-b88a-420b-a3f7-645c18793b4b","workPeriodId":"1b633124-f62c-4026-b679-213cf5812689","challengeId":"4332acc6-3a33-4b7b-af4c-bd2c1ffcfb8e","amount":1400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.325Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"04ef47ac-8f4d-402f-b9fd-48b2b1d9003d","workPeriodId":"1bbc86c8-8c74-4d78-9706-25c4c99721f3","challengeId":"fa909769-f5f7-41fb-94bb-80db62e21a5e","amount":800,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"84c1c956-e03d-4e19-a5a8-a4086c9658eb","workPeriodId":"1e2c732e-ac1f-47ad-939b-22b2078124e5","challengeId":"604910b2-7644-4b9d-a185-0054e61c83fc","amount":1800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"c051c3da-34bb-4deb-8921-04e5d2fa0bcc","workPeriodId":"2430fb35-826a-4e9f-8fb6-8dbcb035d505","challengeId":"25fd805c-49cd-443f-ba0d-813c33a6d8ad","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"cc13acfd-fc06-40e5-aefe-5050429ee4f2","workPeriodId":"2463003f-ee60-4aba-b989-b63babcd9b8b","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":1200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"58c6431a-061a-41bd-a3bd-c8effba62e11","workPeriodId":"2cbe3836-5961-4d58-b8f7-44b84ddf3fc5","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":900,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"efe0e4b5-e6dd-4c1a-a0e5-1f5e0ff91df9","workPeriodId":"309f65e8-b0b5-4cbb-ba60-9b36ccba4bd5","challengeId":"01332fa9-0505-416d-9084-39b136dbd300","amount":1200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"298ac627-e6d7-47b0-ad1d-83de291addf7","workPeriodId":"30c89d78-df85-44ed-92b2-b683d8960fc2","challengeId":"f7e40a0c-a302-4989-a3bd-7587fee3c367","amount":300,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-16T19:13:23.714Z"},{"id":"bf80eca9-8323-4f96-9a3b-8553d6f1e0ce","workPeriodId":"374e2065-40cb-4651-a55c-81a0675dc00d","challengeId":"03c69d02-9188-436e-b4c9-08f39e46f413","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"338d2d7d-2c59-4513-b560-55e8982fd7c7","workPeriodId":"3829c216-ef3f-466c-93da-3a88a961442f","challengeId":"2a0db660-def2-4117-90e8-01cd1271c726","amount":1400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"491f6e93-e80f-46eb-9637-ee84fe7ace9b","workPeriodId":"40ae1e8f-24be-4b51-885c-51f08e15f0df","challengeId":"c2b7a2cc-4633-4f3a-ab39-f7122a6890b6","amount":1600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"cb94d710-fa3c-4333-b8a9-39ec053a665d","workPeriodId":"428fec88-b305-4816-b5ef-be2b4e91c21a","challengeId":"93f594e9-5396-416a-8212-87bee614a38f","amount":1200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"155eaab2-ef74-484c-b1d7-6534dde58b66","workPeriodId":"437d4281-43ec-4de3-85e4-51d298388ce5","challengeId":"5ba2d9df-b3ba-4f5f-bee5-228eb46b2c37","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"11c07a5c-a077-4719-83ba-c48db7e63c01","workPeriodId":"442b0543-e887-42be-9ff5-5fee825526be","challengeId":"d7c21199-a435-41b8-a2ac-5e5bdd021c5e","amount":1400,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"4ce8cf4a-2585-4454-81d4-e5446c9a3f75","workPeriodId":"4a2c581f-c626-44cb-8ada-58f0172e8b4d","challengeId":"ee9bcdd0-0d0d-4414-88cb-d14255f996a5","amount":350,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-16T19:13:23.714Z"},{"id":"8ff6188f-b4e6-4f6e-b2d4-2a622ae50c4f","workPeriodId":"4bfdc253-e39a-4cfa-9a45-2cfc6e93cc6f","challengeId":"f151a5a1-6b28-4f59-bdde-6e73498faa84","amount":450,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"5192e519-30f5-42d6-877f-5c2b786d91c7","workPeriodId":"4db82b0b-4d6f-4e9a-b957-ab405b2c2df2","challengeId":"93f594e9-5396-416a-8212-87bee614a38f","amount":600,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-16T19:13:23.714Z"},{"id":"8ca85158-a850-4cae-97f0-5873a9225ff8","workPeriodId":"531754f3-405e-42eb-932a-c1ce7b9386e7","challengeId":"b42b8f40-9a4d-45d1-814e-59da5c7a1fd9","amount":1200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"4a81c6a3-18d9-441b-ae64-3aa9def336ef","workPeriodId":"5392acee-b504-4720-95fa-dab585acb607","challengeId":"78154e5c-feed-4dbf-84ec-775395139211","amount":200,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-16T19:13:23.714Z"},{"id":"a26b8cae-a1df-4843-a192-0735f235bf78","workPeriodId":"558b4685-4932-492e-99e1-2830c10f8275","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"a94b6f43-de89-4fd2-9a1d-d8a2cce02702","workPeriodId":"584c931b-da72-416e-a011-eac5fe34f42f","challengeId":"d55fae30-3072-462e-b8bd-eb2eec664e65","amount":1600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"eb63dfc7-14d7-4cae-a25e-3e33a04601cf","workPeriodId":"5ddc132b-3205-45e3-bfe9-f1a4f939885e","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":300,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"d827ed01-5153-4774-8450-bace2521a6d1","workPeriodId":"619a0835-730f-47ec-820e-3959821aec51","challengeId":"d40cb9c5-b3bd-45a1-802c-a50fefb020b9","amount":1000,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"f950e52e-5a52-4ee8-af5f-e6c42e9b400b","workPeriodId":"64de2244-6fcf-45ac-8a89-a9b3420e4476","challengeId":"6c04d456-bb38-43c8-a538-f5cc6caaa540","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"283f9c3b-7f0a-4792-9661-ced7cbdb340d","workPeriodId":"6a1180b8-38af-4bd0-8a5f-a60626e0bc95","challengeId":"9a995b78-0542-41be-a926-f3df57c2f873","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"09ea6f03-4489-496c-817c-e9279a58c0ad","workPeriodId":"6da7d347-7492-43b1-a49d-8a6e1daf9b22","challengeId":"78154e5c-feed-4dbf-84ec-775395139211","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"7d782624-243e-497b-90ca-cc00ae29ebf2","workPeriodId":"6e1dc024-d437-4d9f-92e9-561db713a19a","challengeId":"afcbc3bc-9077-4978-bf9c-acddb48e6518","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"11918ff9-5f18-445d-ae90-762b3ebe44ca","workPeriodId":"6ed667a5-275e-4f27-984b-34dff5f8a1ff","challengeId":"c89d357f-afd1-4757-824f-2cf94e2890c6","amount":250,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"9fe78619-5c1c-4b22-8d6f-ebf9a9502432","workPeriodId":"703bc625-9144-4a9f-a91b-445e171d8ea9","challengeId":"6c04d456-bb38-43c8-a538-f5cc6caaa540","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"7cf85ce0-ef8c-4152-8623-9a1325db6daa","workPeriodId":"729a2396-2b33-4185-8ce8-d929dbf4a472","challengeId":"fbf8efda-fe4b-4b72-99dd-573b79d27bd8","amount":200,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"e8aee371-1f26-4475-8459-9c134fa6f3c6","workPeriodId":"731db5d7-bb79-45f4-b1b2-9f60d30f7966","challengeId":"ee9bcdd0-0d0d-4414-88cb-d14255f996a5","amount":700,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"dec8615b-c823-4fff-bc77-fa0614b8d09c","workPeriodId":"7f8f3a25-b1d2-4e36-a543-fcaae57a32f5","challengeId":"fe3e4056-82e3-4df4-b699-a1f3d8ab5e53","amount":700,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"c4e316ca-a46f-4fbc-96a6-6fe6665c3b49","workPeriodId":"829165cb-0150-48e7-995c-f5b4d1a51d3b","challengeId":"d937a822-4a9b-40db-afe6-fe1285e3f7f9","amount":900,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"12b0bcfc-59ae-478c-bb32-cb18d1d0244c","workPeriodId":"84431dac-019d-4987-9817-15f5f000d2db","challengeId":"a07ea88f-c52b-4023-8730-c4364efd0dd2","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"8c9ed23c-12c7-4a8b-8e91-6fd3b3fc43a4","workPeriodId":"8b7b49de-29b1-4a0c-bb67-e70cc700fcfd","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":450,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"621d793b-0ead-4d99-a119-e32af526ece7","workPeriodId":"8c8cedf3-0bb6-4063-8a3a-faf1626da384","challengeId":"ad04dcee-9a3c-4345-b0b5-783ce98e94b2","amount":900,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"56cb3aef-531b-4a26-817e-4b9629212c9a","workPeriodId":"90d99323-ba57-4a18-b50f-78f387033c70","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":450,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"a1ffc559-703a-4c35-8ba3-73a03c3454af","workPeriodId":"93b0f03b-219b-41d5-bb1e-f125651b1b0e","challengeId":"9fca67f9-3641-4982-8a82-e86b1850efc8","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"a5904ae3-7524-4709-b798-20c4a2193f10","workPeriodId":"93e69f99-cb1c-418e-aa41-ab2181b4bcfd","challengeId":"ed56a1c7-a965-4ab6-9cf0-0d7c14cd7db3","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"821b38e8-657d-4f72-b27a-dd975c506ced","workPeriodId":"9b6fc85b-3694-4e6c-9ebf-fe9ccf7881ba","challengeId":"61f5185b-4ee1-4df3-9c6f-52f5bf0cbfc5","amount":500,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"2417df2c-8e29-4868-aeb8-5ec0ff67713e","workPeriodId":"9bfbd49a-e6bb-45c3-965d-ed4f95f0878a","challengeId":"f01ba8da-c891-472d-9ed6-74b91ed9b407","amount":400,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"5116d4ea-2c1a-4be6-b335-bd531b8d5734","workPeriodId":"a35bb205-361b-4b2d-9828-55501ae9d190","challengeId":"b42b8f40-9a4d-45d1-814e-59da5c7a1fd9","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-16T19:13:23.714Z"},{"id":"8fdfe90b-2155-4a71-a610-4689106ced34","workPeriodId":"b21f921a-4b23-423d-814b-d31f5cba7f64","challengeId":"963784fd-4174-458c-a311-a5b8333d66ab","amount":300,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"dd9c842a-f577-43c2-8f17-cc940f26f0d8","workPeriodId":"b4566e24-4fa8-4e82-9950-f62134bb00df","challengeId":"b67cbbc5-3384-4ea6-8504-d3fe83a6e238","amount":700,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.326Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"7e41ca7f-d3c0-4d70-9daf-ee52c93695c7","workPeriodId":"b5261ee2-bc4d-4c3a-9d30-6703bfdcfbc5","challengeId":"9d49655f-99f6-4e67-9819-a117ef746272","amount":500,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"b8d44e83-922c-4c2c-8567-5764794e03f3","workPeriodId":"b682660e-488e-4033-aaf3-ef37248abc90","challengeId":"d7c21199-a435-41b8-a2ac-5e5bdd021c5e","amount":700,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-16T19:13:23.714Z"},{"id":"c117de76-965f-4069-aefb-8dd97f95112c","workPeriodId":"b8a8b558-0cb9-46d0-ba9d-2222f3fbdb63","challengeId":"59d08064-e1b4-4e78-82d8-b2d7ffa6f0b1","amount":900,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"fda2013c-da68-4601-8d13-d0f4cffd081c","workPeriodId":"bc8611f0-4ac2-49b2-b776-59ed2b759d1d","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"be07bfc8-032c-41f7-a247-a4724f65617c","workPeriodId":"bd54bcaf-5278-467f-a166-865048774d0e","challengeId":"45e33cee-7c83-4288-8187-6858b0c759eb","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"efa8cd14-c93f-4e6c-be53-596f02db8c96","workPeriodId":"bf61dad8-841a-4913-93f6-b2ae516b8b11","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"eb9c9a83-fe94-4f51-b9f0-c2d9671e87f6","workPeriodId":"c5f6ae8f-2976-46d1-bd66-58eeb58ca045","challengeId":"68e6a32e-6c31-4266-ba3b-9d2f63be4274","amount":900,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.361Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"c20796c8-76b0-40e8-9bee-db406c93daaf","workPeriodId":"c7ff2acc-a4c2-4e8b-a905-813dd9d1b293","challengeId":"513ab4c6-0aa4-482b-a184-87f8447b145b","amount":1800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.390Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"8fad32f7-cb40-416f-ab24-86cf1c7870ef","workPeriodId":"c9685cb2-9f4a-497e-ae99-deed7b16cc34","challengeId":"f7e40a0c-a302-4989-a3bd-7587fee3c367","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"310384cb-6e85-4f7d-a6d2-8c03ca27871d","workPeriodId":"d049e7bc-c827-482b-9ec6-b87d9289d1cd","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":900,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"2a122a93-e778-4eb9-868c-5f38b8b9bb4e","workPeriodId":"da8abd64-2878-4e09-b3b1-41a27a0576d4","challengeId":"25a7c442-427b-4b6d-9c41-112dbd420c0d","amount":800,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"767897c3-bbc2-4b1a-9843-5a6bd82e29b0","workPeriodId":"dcc310cf-ea4a-4637-9bf5-5baaabea67b3","challengeId":"61044188-965e-40df-94c4-9fa9a9499b25","amount":1000,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"50f7a6fa-a04d-4873-8fd0-037be2f14425","workPeriodId":"e19bddc5-38ac-43c9-8273-bc9069de26b3","challengeId":"419fbb3d-921d-4613-a87e-337f38d21885","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.523Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"11ea987f-f218-4d2b-b656-0741208539f2","workPeriodId":"f575df2d-f170-4251-9042-b17ca5e99ca5","challengeId":"0de972b8-6cc9-4625-9760-1c77561c29e9","amount":600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-16T19:13:23.714Z","updatedAt":"2021-04-21T20:19:56.934Z"},{"id":"2519d7f9-81c8-448c-aec2-aa78d6d6a962","workPeriodId":"f70509c0-baed-4ff1-8022-12441251f7af","challengeId":"fd051497-6050-4edf-b8f7-780128f64dc5","amount":300,"status":"cancelled","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":null,"createdAt":"2021-04-14T22:01:45.324Z","updatedAt":"2021-04-21T20:19:56.934Z"}]} \ 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 ec79947b..d636cfc0 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "b1144d77-699c-47be-864e-fbe99e7f5c14", + "_postman_id": "fb3b4365-f23e-4e88-9fce-5dcd94c130b8", "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-27\",\r\n \"endDate\": \"2020-10-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\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}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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,7 +3085,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-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-27\",\r\n \"endDate\": \"2021-01-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}", "options": { "raw": { "language": "json" @@ -2906,6 +3104,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}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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 + } + ] + } + }, + "response": [] + }, { "name": "create resource booking with connect user", "event": [ @@ -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-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" @@ -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-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" @@ -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-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" @@ -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" } @@ -3060,7 +3363,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-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" @@ -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,11 +3421,24 @@ }, { "name": "get resource booking with m2m read", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", + "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_read_resource_booking}}" } @@ -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": [ @@ -3207,6 +3577,19 @@ }, { "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": [ @@ -3247,12 +3630,12 @@ }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { @@ -3262,7 +3645,7 @@ }, { "key": "status", - "value": "sourcing", + "value": "assigned", "disabled": true }, { @@ -3277,6 +3660,19 @@ }, { "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": [ @@ -3317,12 +3713,12 @@ }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { @@ -3332,7 +3728,7 @@ }, { "key": "status", - "value": "sourcing", + "value": "assigned", "disabled": true } ] @@ -3342,6 +3738,19 @@ }, { "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": [ @@ -3377,12 +3786,12 @@ }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { @@ -3401,6 +3810,17 @@ }, { "name": "search resource bookings with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "GET", "header": [ @@ -3436,12 +3856,12 @@ }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { @@ -3460,6 +3880,21 @@ }, { "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": [ @@ -3495,12 +3930,12 @@ }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "2020-09-27", "disabled": true }, { @@ -3519,6 +3954,19 @@ }, { "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": [ @@ -3530,7 +3978,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 \"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-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}", "options": { "raw": { "language": "json" @@ -3551,52 +3999,122 @@ "response": [] }, { - "name": "put resource booking with m2m update", + "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": "PUT", + "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_update_resource_booking}}" + "value": "Bearer {{token_bookingManager}}" } ], - "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}", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingIdCreatedByM2M}}" + "work-periods" + ], + "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": "put resource booking with connect user", + "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_connectUser}}" + "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\": \"{{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\": \"{{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}", "options": { "raw": { "language": "json" @@ -3604,98 +4122,137 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ "resourceBookings", - "{{resourceBookingId}}" + "{{resourceBookingIdCreatedByM2M}}" ] } }, "response": [] }, { - "name": "put resource booking with member", + "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": "PUT", + "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "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}", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "raw": "{{URL}}/work-periods?sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingId}}" - ] - } - }, - "response": [] - }, - { - "name": "put resource booking with user id not exist", - "request": { - "method": "PUT", - "header": [ - { - "key": "Authorization", - "type": "text", - "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}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", - "host": [ - "{{URL}}" + "work-periods" ], - "path": [ - "resourceBookings", - "{{resourceBookingId}}" + "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 + } ] } }, "response": [] }, { - "name": "put resource booking with invalid token", + "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 invalid_token" + "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-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}", "options": { "raw": { "language": "json" @@ -3716,19 +4273,34 @@ "response": [] }, { - "name": "patch resource booking with booking manager", + "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": "PATCH", + "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer {{token_member}}" } ], "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 \"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}", "options": { "raw": { "language": "json" @@ -3749,19 +4321,34 @@ "response": [] }, { - "name": "patch resource booking with m2m update", + "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": "PATCH", + "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_update_resource_booking}}" + "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 \"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}", "options": { "raw": { "language": "json" @@ -3769,32 +4356,47 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ "resourceBookings", - "{{resourceBookingIdCreatedByM2M}}" + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "patch resource booking with connect user", + "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": "PATCH", + "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer invalid_token" } ], "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 \"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}", "options": { "raw": { "language": "json" @@ -3815,19 +4417,32 @@ "response": [] }, { - "name": "patch resource booking with member", + "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": "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 \"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}", "options": { "raw": { "language": "json" @@ -3848,19 +4463,32 @@ "response": [] }, { - "name": "patch resource booking with user id not exist", + "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": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_m2m_update_resource_booking}}" } ], "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-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" @@ -3868,32 +4496,47 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ "resourceBookings", - "{{resourceBookingId}}" + "{{resourceBookingIdCreatedByM2M}}" ] } }, "response": [] }, { - "name": "patch resource booking with invalid token", + "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 invalid_token" + "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-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-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" @@ -3914,9 +4557,24 @@ "response": [] }, { - "name": "delete resource booking with member", + "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": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -3926,7 +4584,7 @@ ], "body": { "mode": "raw", - "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}", "options": { "raw": { "language": "json" @@ -3947,19 +4605,34 @@ "response": [] }, { - "name": "delete resource booking with connect user", + "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": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_userId_not_exist}}" } ], "body": { "mode": "raw", - "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}", "options": { "raw": { "language": "json" @@ -3980,19 +4653,34 @@ "response": [] }, { - "name": "delete resource booking with booking manager", + "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": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer invalid_token" } ], "body": { "mode": "raw", - "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}", "options": { "raw": { "language": "json" @@ -4013,52 +4701,123 @@ "response": [] }, { - "name": "delete resource booking with m2m delete", + "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": "DELETE", + "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_delete_resource_booking}}" + "value": "Bearer {{token_bookingManager}}" } ], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "raw": "{{URL}}/work-periods?perPage=1&sortBy=startDate&sortOrder=asc&resourceBookingId={{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingIdCreatedByM2M}}" + "work-periods" + ], + "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": "delete resource booking with invalid token", + "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": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "", + "raw": "{\r\n \"paymentStatus\": \"completed\"\r\n}", "options": { "raw": { "language": "json" @@ -4066,366 +4825,233 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", + "raw": "{{URL}}/work-periods/{{workPeriodIdForPaid}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingId}}" + "work-periods", + "{{workPeriodIdForPaid}}" ] } }, "response": [] - } - ] - }, - { - "name": "Taas Teams", - "item": [ + }, { - "name": "GET /taas-teams", + "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": "GET", + "method": "PATCH", "header": [ { "key": "Authorization", - "value": "Bearer {{token_bookingManager}}", - "type": "text" + "type": "text", + "value": "Bearer {{token_bookingManager}}" } ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams?perPage=10&page=1&name=*taas*&sortBy=lastActivityAt&sortOrder=desc", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams" - ], - "query": [ - { - "key": "perPage", - "value": "10" - }, - { - "key": "page", - "value": "1" - }, - { - "key": "name", - "value": "*taas*", - "description": "case-insensitive; support wildcard match" - }, - { - "key": "sortBy", - "value": "lastActivityAt", - "description": "allows: createdAt, updatedAt, lastActivityAt, id, status, name, type, best match" - }, - { - "key": "sortOrder", - "value": "desc", - "description": "allows: asc, desc" - } + "resourceBookings", + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "GET /taas-teams with booking manager", + "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": "GET", + "method": "PATCH", "header": [ { "key": "Authorization", - "value": "Bearer {{token_bookingManager}}", - "type": "text" + "type": "text", + "value": "Bearer {{token_bookingManager}}" } ], + "body": { + "mode": "raw", + "raw": "{\r\n \"startDate\": \"2020-10-04\",\r\n \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams?perPage=10&page=1&name=*taas*&sortBy=lastActivityAt&sortOrder=desc", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams" - ], - "query": [ - { - "key": "perPage", - "value": "10" - }, - { - "key": "page", - "value": "1" - }, - { - "key": "name", - "value": "*taas*", - "description": "case-insensitive; support wildcard match" - }, - { - "key": "sortBy", - "value": "lastActivityAt", - "description": "allows: createdAt, updatedAt, lastActivityAt, id, status, name, type, best match" - }, - { - "key": "sortOrder", - "value": "desc", - "description": "allows: asc, desc" - } + "resourceBookings", + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "GET /taas-teams with m2m read", + "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": "GET", + "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_read_taas_team}}" + "value": "Bearer {{token_member}}" } ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams" + "resourceBookings", + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "GET /taas-teams/:id", + "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": "GET", + "method": "DELETE", "header": [ { "key": "Authorization", - "value": "Bearer {{token_bookingManager}}", - "type": "text" + "type": "text", + "value": "Bearer {{token_connectUser}}" } ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams/{{projectId}}", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - "{{projectId}}" + "resourceBookings", + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "GET /taas-teams/:id with booking manager", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token_bookingManager}}", - "type": "text" - } - ], - "url": { - "raw": "{{URL}}/taas-teams/:projectId", - "host": [ - "{{URL}}" - ], - "path": [ - "taas-teams", - ":projectId" - ], - "variable": [ - { - "key": "projectId", - "value": "16705" - } - ] - } - }, - "response": [] - }, - { - "name": "GET /taas-teams/:id with m2m read", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_m2m_read_taas_team}}" - } - ], - "url": { - "raw": "{{URL}}/taas-teams/{{projectId}}", - "host": [ - "{{URL}}" - ], - "path": [ - "taas-teams", - "{{projectId}}" - ] - } - }, - "response": [] - }, - { - "name": "GET /taas-teams/:id/jobs/:jobId", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token_bookingManager}}", - "type": "text" - } - ], - "url": { - "raw": "{{URL}}/taas-teams/{{projectId}}/jobs/{{jobId}}", - "host": [ - "{{URL}}" - ], - "path": [ - "taas-teams", - "{{projectId}}", - "jobs", - "{{jobId}}" - ] - } - }, - "response": [] - }, - { - "name": "GET /taas-teams/:id/jobs/:jobId with booking manager", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token_bookingManager}}", - "type": "text" + "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" } - ], - "url": { - "raw": "{{URL}}/taas-teams/:projectId/jobs/:jobId", - "host": [ - "{{URL}}" - ], - "path": [ - "taas-teams", - ":projectId", - "jobs", - ":jobId" - ], - "variable": [ - { - "key": "projectId", - "value": "16705" - }, - { - "key": "jobId", - "value": "948a25a6-086f-4a96-aad5-9ccd2d3e87b2" - } - ] } - }, - "response": [] - }, - { - "name": "GET /taas-teams/:id/jobs/:jobId with m2m read", + ], "request": { - "method": "GET", + "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_m2m_read_taas_team}}" - } - ], - "url": { - "raw": "{{URL}}/taas-teams/{{projectId}}/jobs/{{jobId}}", - "host": [ - "{{URL}}" - ], - "path": [ - "taas-teams", - "{{projectId}}", - "jobs", - "{{jobId}}" - ] - } - }, - "response": [] - }, - { - "name": "GET /taas-teams/skills", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token_member}}", - "type": "text" - } - ], - "url": { - "raw": "{{URL}}/taas-teams/skills?perPage=10&page=1&orderBy=name", - "host": [ - "{{URL}}" - ], - "path": [ - "taas-teams", - "skills" - ], - "query": [ - { - "key": "perPage", - "value": "10" - }, - { - "key": "page", - "value": "1" - }, - { - "key": "orderBy", - "value": "name", - "description": "possible values are defined by /v5/skills" - } - ] - } - }, - "response": [] - }, - { - "name": "POST /taas-teams/email - team-issue-report", - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token_member}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "{\n \"template\": \"team-issue-report\",\n \"data\": {\n \"projectName\": \"TaaS Project Name\",\n \"projectId\": 12345,\n \"reportText\": \"I have issue with ...\"\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -4433,37 +5059,45 @@ } }, "url": { - "raw": "{{URL}}/taas-teams/email", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - "email" + "resourceBookings", + "{{resourceBookingId}}" ] } }, "response": [] }, { - "name": "POST /taas-teams/email - member-issue-report", + "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": "POST", + "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" - }, - { - "key": "Content-Type", - "type": "text", - "value": "application/json" + "value": "Bearer {{token_m2m_delete_resource_booking}}" } ], "body": { "mode": "raw", - "raw": "{\n \"template\": \"member-issue-report\",\n \"data\": {\n \"projectName\": \"TaaS Project Name\",\n \"projectId\": 12345,\n \"userHandle\": \"pshah_manager\",\n \"reportText\": \"I have issue with ...\"\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -4471,37 +5105,47 @@ } }, "url": { - "raw": "{{URL}}/taas-teams/email", + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - "email" + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" ] } }, "response": [] }, { - "name": "POST /taas-teams/email - extension-request", + "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": "POST", + "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" - }, - { - "key": "Content-Type", - "type": "text", - "value": "application/json" + "value": "Bearer invalid_token" } ], "body": { "mode": "raw", - "raw": "{\n \"template\": \"extension-request\",\n \"data\": {\n \"projectName\": \"TaaS Project Name\",\n \"projectId\": 12345,\n \"userHandle\": \"pshah_manager\",\n \"reportText\": \"I would like to keep working with this member for 2 months...\"\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -4509,37 +5153,157 @@ } }, "url": { - "raw": "{{URL}}/taas-teams/email", + "raw": "{{URL}}/resourceBookings/{{resourceBookingId}}", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - "email" - ] + "resourceBookings", + "{{resourceBookingId}}" + ] } }, "response": [] + } + ] + }, + { + "name": "Work Periods", + "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 resource booking", + "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(\"resourceBookingId\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "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-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" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + } + ] }, { - "name": "POST /taas-teams/:id/members", + "name": "create work period with booking manager", + "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(\"workPeriodId\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "POST", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" - }, - { - "key": "Content-Type", - "type": "text", - "value": "application/json" + "value": "Bearer {{token_bookingManager}}" } ], "body": { "mode": "raw", - "raw": "{\n \"handles\": [\n \"tester1234\",\n \"non-existing\"\n ],\n \"emails\": [\n \"non-existing@domain.com\",\n \"email@domain.com\"\n ]\n}", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -4547,590 +5311,6819 @@ } }, "url": { - "raw": "{{URL}}/taas-teams/:id/members", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - ":id", - "members" - ], - "variable": [ - { - "key": "id", - "value": "16705" - } + "work-periods" ] } }, "response": [] }, { - "name": "GET /taas-teams/:id/members", + "name": "create work period with m2m create", + "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(\"workPeriodIdCreatedByM2M\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { - "method": "GET", + "method": "POST", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" - }, - { - "key": "Content-Type", - "type": "text", - "value": "application/json" + "value": "Bearer {{token_m2m_create_work_period}}" } ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-14\",\r\n \"endDate\": \"2021-03-20\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams/:id/members?role=customer&fields=id,userId,role,createdAt,updatedAt,createdBy,updatedBy,handle,photoURL,workingHourStart,workingHourEnd,timeZone,email", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - ":id", - "members" - ], - "query": [ - { - "key": "role", - "value": "customer" - }, - { - "key": "fields", - "value": "id,userId,role,createdAt,updatedAt,createdBy,updatedBy,handle,photoURL,workingHourStart,workingHourEnd,timeZone,email" - } - ], - "variable": [ - { - "key": "id", - "value": "16705" - } + "work-periods" ] } }, "response": [] }, { - "name": "GET /taas-teams/:id/invites", + "name": "create work period 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": "GET", + "method": "POST", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" - }, - { - "key": "Content-Type", - "type": "text", - "value": "application/json" + "value": "Bearer {{token_connectUser}}" } ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams/:id/invites?fields=createdAt,deletedAt,role,updatedBy,createdBy,id,projectId,userId,email,deletedBy,updatedAt,status", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - ":id", - "invites" - ], - "query": [ - { - "key": "fields", - "value": "createdAt,deletedAt,role,updatedBy,createdBy,id,projectId,userId,email,deletedBy,updatedAt,status" - } - ], - "variable": [ - { - "key": "id", - "value": "16705" - } + "work-periods" ] } }, "response": [] }, { - "name": "DELETE /taas-teams/:id/members/:projectMemberId", + "name": "create work period 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", + "method": "POST", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" - }, - { - "key": "Content-Type", - "type": "text", - "value": "application/json" + "value": "Bearer {{token_member}}" } ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/taas-teams/:id/members/:projectMemberId", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "taas-teams", - ":id", - "members", - ":projectMemberId" - ], - "variable": [ - { - "key": "id", - "value": "16705" - }, - { - "key": "projectMemberId", - "value": "14327" - } + "work-periods" ] } }, "response": [] - } - ] - }, - { - "name": "health check", - "item": [ + }, { - "name": "health check", + "name": "create work period 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": "GET", - "header": [], + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "{{URL}}/health", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "health" + "work-periods" ] } }, "response": [] - } - ] - }, - { - "name": "Create Demo Data For Team", - "item": [ + }, { - "name": "Get Users", - "item": [ + "name": "create work period with invalid token", + "event": [ { - "name": "Get Users", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "var demoUsers = 20;", - "", - "pm.test('We need to have at least ' + demoUsers + ' demo userIds. Define them in {{demoUserIdN}} variables.', function () {", - " for (var i = 0; i < demoUsers; i++) {", - " var variableName = \"demoUserId\" + (i + 1);", - " var existentValue = pm.variables.get(variableName);", - " var user = data[i];", - "", - " pm.expect(!!user || !!existentValue).to.be.true;", - "", - " postman.setEnvironmentVariable(variableName, user.id);", - " }", - "});" - ], - "type": "text/javascript" - } + "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": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{token_bookingManager}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "https://api.topcoder-dev.com/v5/users?perPage=20", - "protocol": "https", - "host": [ - "api", - "topcoder-dev", - "com" - ], - "path": [ - "v5", - "users" - ], - "query": [ - { - "key": "perPage", - "value": "20" - } - ] - } - }, - "response": [] + "path": [ + "work-periods" + ] } - ] + }, + "response": [] }, { - "name": "Create job #1 \"sourcing\"", - "item": [ + "name": "create work period with missing parameter 1", + "event": [ { - "name": "create job #1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJobId1\",data.id);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "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(\"\\\"workPeriod.resourceBookingId\\\" is required\")\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job1\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 13,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"ee4c50c1-c8c3-475e-b6b6-edbd136a19d6\",\n \"89139c80-d0a2-47c2-aa16-14589d5afd10\",\n \"9f2d9127-6a2e-4506-ad76-c4ab63577b09\",\n \"9515e7ee-83b6-49d1-ba5c-6c59c5a8ef1b\",\n \"c854ab55-5922-4be1-8ecc-b3bc1f8629af\",\n \"8456002e-fa2d-44f0-b0e7-86b1c02b6e4c\",\n \"114b4ec8-805e-4c60-b351-14a955a991a9\",\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\",\n \"23839f38-6f19-4de9-9d28-f020056bca73\",\n \"289e42a3-23e9-49be-88e1-6deb93cd8c31\",\n \"b403f209-63b5-42bc-9b5f-1564416640d8\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobs", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] } - ] + }, + "response": [] }, { - "name": "Create job #2 \"in-review\"", - "item": [ + "name": "create work period with missing parameter 2", + "event": [ { - "name": "create job #2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJobId2\",data.id);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "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(\"\\\"workPeriod.endDate\\\" is required\")\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job2\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\",\n \"23839f38-6f19-4de9-9d28-f020056bca73\",\n \"289e42a3-23e9-49be-88e1-6deb93cd8c31\",\n \"b403f209-63b5-42bc-9b5f-1564416640d8\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobs", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } }, - { - "name": "create job #2 candidate 1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob1candidateId1\",data.id);" - ], - "type": "text/javascript" - } - } + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with missing parameter 3", + "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(\"\\\"workPeriod.paymentStatus\\\" is required\")\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId1}}\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } }, - { - "name": "create job #2 candidate 2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob1candidateId2\",data.id);" - ], - "type": "text/javascript" - } - } + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 1", + "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(\"\\\"workPeriod.resourceBookingId\\\" must be a valid GUID\")\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId2}}\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"aaa-aaa\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 2", + "event": [ { - "name": "create job #2 candidate 3", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } + "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(\"\\\"workPeriod.startDate\\\" must be in YYYY-MM-DD format\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"07-03-2021\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 3", + "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(\"startDate should be always Sunday\")\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId3}}\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-06\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } }, - { - "name": "create job #2 candidate 4", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } - } + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 4", + "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(\"endDate should be always the next Saturday\")\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId4}}\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-14\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 5", + "event": [ { - "name": "create job #2 candidate 5", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } + "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(\"\\\"workPeriod.daysWorked\\\" must be a number\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": \"aa\",\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 6", + "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(`Key (resource_booking_id, start_date, end_date)=(${pm.environment.get('resourceBookingId')}, 2021-03-07, 2021-03-13) already exists.`)\r", + "});" ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId5}}\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" } - }, - "response": [] + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with invalid parameter 7", + "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(\"\\\"workPeriod.paymentStatus\\\" must be one of [pending, partially-completed, completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"paid\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "get work period 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}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period with m2m read 1", + "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_read_work_period}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period with m2m read 2", + "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_read_work_period_and_payment}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}?fromDb=true", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ], + "query": [ + { + "key": "fromDb", + "value": "true" + } + ] + } + }, + "response": [] + }, + { + "name": "get work period 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_connectUser}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "search work periods 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}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "35", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "resourceBookingId", + "value": "{{resourceBookingId}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{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 + } + ] + } + }, + "response": [] + }, + { + "name": "search work periods with m2m all 1", + "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_work_period}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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": "resourceBookingId", + "value": "{{resourceBookingId}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{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 + } + ] + } + }, + "response": [] + }, + { + "name": "search work periods with m2m all 2", + "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_work_period_and_payment}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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": "resourceBookingId", + "value": "{{resourceBookingId}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{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 + } + ] + } + }, + "response": [] + }, + { + "name": "search work periods 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_connectUser}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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": "resourceBookingId", + "value": "{{resourceBookingId}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{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 + } + ] + } + }, + "response": [] + }, + { + "name": "search work periods with member", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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": "resourceBookingId", + "value": "{{resourceBookingId}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{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 + } + ] + } + }, + "response": [] + }, + { + "name": "search work periods with invalid token", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 401', function () {\r", + " pm.response.to.have.status(401);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer invalid_token" + } + ], + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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": "resourceBookingId", + "value": "{{resourceBookingId}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resourceBookingId}},{{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": "111", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "put work period 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 \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period 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_work_period}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-14\",\r\n \"endDate\": \"2021-03-20\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period 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_connectUser}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period 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_member}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period 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_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period 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 invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with missing parameter 1", + "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(\"\\\"data.resourceBookingId\\\" is required\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with missing parameter 2", + "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(\"\\\"data.endDate\\\" is required\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with missing parameter 3", + "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(\"\\\"data.paymentStatus\\\" is required\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 1", + "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(\"\\\"data.resourceBookingId\\\" must be a valid GUID\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"aaa-aaa\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 2", + "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(\"\\\"data.startDate\\\" must be in YYYY-MM-DD format\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"07-03-2021\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 3", + "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(\"startDate should be always Sunday\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-06\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 4", + "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(\"endDate should be always the next Saturday\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-14\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 5", + "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(\"\\\"data.daysWorked\\\" must be a number\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": \"aa\",\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 6", + "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(`Key (resource_booking_id, start_date, end_date)=(${pm.environment.get('resourceBookingId')}, 2021-03-14, 2021-03-20) already exists.`)\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-14\",\r\n \"endDate\": \"2021-03-20\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period with invalid parameter 7", + "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(\"\\\"data.paymentStatus\\\" must be one of [pending, partially-completed, completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"paid\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period 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": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period 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": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_work_period}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-14\",\r\n \"endDate\": \"2021-03-20\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period 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 \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period 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 \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period 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_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period 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 invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-21\",\r\n \"endDate\": \"2021-03-27\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 1", + "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(\"\\\"data.resourceBookingId\\\" must be a valid GUID\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"aaa-aaa\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 2", + "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(\"\\\"data.startDate\\\" must be in YYYY-MM-DD format\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"07-03-2021\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 3", + "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(\"startDate should be always Sunday\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-06\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 4", + "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(\"endDate should be always the next Saturday\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-14\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 5", + "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(\"\\\"data.daysWorked\\\" must be a number\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": \"aa\",\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 6", + "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(`Key (resource_booking_id, start_date, end_date)=(${pm.environment.get('resourceBookingId')}, 2021-03-14, 2021-03-20) already exists.`)\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-14\",\r\n \"endDate\": \"2021-03-20\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period with invalid parameter 7", + "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(\"\\\"data.paymentStatus\\\" must be one of [pending, partially-completed, completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"paid\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete work period 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete work period 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_connectUser}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete work period with booking manager", + "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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete work period 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_work_period}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "delete work period 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete work period not found", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 404', function () {\r", + " pm.response.to.have.status(404);\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Work Period Payments", + "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 resource booking", + "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(\"resourceBookingId\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{project_id_17234}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\r\n \"startDate\": \"2020-09-27\",\r\n \"endDate\": \"2020-10-27\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create work period", + "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(\"workPeriodId\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "create work period with m2m", + "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(\"workPeriodIdCreatedByM2M\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_create_work_period}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resourceBookingId}}\",\r\n \"startDate\": \"2021-03-14\",\r\n \"endDate\": \"2021-03-20\",\r\n \"daysWorked\": 3,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "create work period payment with boooking manager", + "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(\"workPeriodPaymentId\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with m2m create", + "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(\"workPeriodPaymentIdCreatedByM2M\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_create_work_period_payment}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodIdCreatedByM2M}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment 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": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_connectUser}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment 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": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment 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": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment 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": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with missing workPeriodId", + "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(\"\\\"workPeriodPayment.workPeriodId\\\" is required\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with invalid workPeriodId 1", + "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(\"\\\"workPeriodPayment.workPeriodId\\\" must be a valid GUID\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"aaa-bb-c\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with invalid workPeriodId 2", + "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(\"\\\"workPeriodPayment.workPeriodId\\\" must be a string\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": 123,\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with invalid amount 1", + "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(\"\\\"workPeriodPayment.amount\\\" must be a number\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": \"abc\",\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with invalid amount 2", + "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(\"\\\"workPeriodPayment.amount\\\" must be greater than 0\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 0,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with invalid status 1", + "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(\"\\\"workPeriodPayment.status\\\" must be one of [completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1200,\r\n \"status\": 123\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "create work period payment with invalid status 2", + "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(\"\\\"workPeriodPayment.status\\\" must be one of [completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1200,\r\n \"status\": \"invalid-status\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] + }, + { + "name": "get work period payment 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}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period payment 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_work_period_payment}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period payment 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": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}?fromDb=true", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ], + "query": [ + { + "key": "fromDb", + "value": "true" + } + ] + } + }, + "response": [] + }, + { + "name": "get work period payment 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": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_connectUser}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "get work period payment 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": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "search work period payments 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}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "50", + "disabled": true + }, + { + "key": "sortBy", + "value": "status", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "workPeriodId", + "value": "{{workPeriodId}}", + "disabled": true + }, + { + "key": "workPeriodIds", + "value": "{{workPeriodId}},{{workPeriodIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "status", + "value": "completed", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "search work period payments 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_work_period_payment}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "50", + "disabled": true + }, + { + "key": "sortBy", + "value": "status", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "workPeriodId", + "value": "{{workPeriodId}}", + "disabled": true + }, + { + "key": "workPeriodIds", + "value": "{{workPeriodId}},{{workPeriodIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "status", + "value": "completed", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "search work period payments 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": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_connectUser}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "50", + "disabled": true + }, + { + "key": "sortBy", + "value": "status", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "workPeriodId", + "value": "{{workPeriodId}}", + "disabled": true + }, + { + "key": "workPeriodIds", + "value": "{{workPeriodId}},{{workPeriodIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "status", + "value": "completed", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "search work period payments 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": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "50", + "disabled": true + }, + { + "key": "sortBy", + "value": "status", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "workPeriodId", + "value": "{{workPeriodId}}", + "disabled": true + }, + { + "key": "workPeriodIds", + "value": "{{workPeriodId}},{{workPeriodIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "status", + "value": "completed", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "search work period payments 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 invalid_token" + } + ], + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "50", + "disabled": true + }, + { + "key": "sortBy", + "value": "status", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "workPeriodId", + "value": "{{workPeriodId}}", + "disabled": true + }, + { + "key": "workPeriodIds", + "value": "{{workPeriodId}},{{workPeriodIdCreatedByM2M}}", + "disabled": true + }, + { + "key": "status", + "value": "completed", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with boooking 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 \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with m2m create", + "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_work_period_payment}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodIdCreatedByM2M}}\",\r\n \"amount\": 1600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment 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_connectUser}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment 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_member}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment 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_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment 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 invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with missing workPeriodId", + "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(\"\\\"data.workPeriodId\\\" is required\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with invalid workPeriodId 1", + "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(\"\\\"data.workPeriodId\\\" must be a valid GUID\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"aaa-bb-c\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with invalid workPeriodId 2", + "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(\"\\\"data.workPeriodId\\\" must be a string\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": 123,\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with invalid amount 1", + "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(\"\\\"data.amount\\\" must be a number\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": \"abc\",\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with invalid amount 2", + "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(\"\\\"data.amount\\\" must be greater than 0\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 0,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with invalid status 1", + "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(\"\\\"data.status\\\" must be one of [completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1200,\r\n \"status\": 123\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "put work period payment with invalid status 2", + "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(\"\\\"data.status\\\" must be one of [completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1200,\r\n \"status\": \"invalid-status\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with boooking 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": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 450,\r\n \"status\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with m2m create", + "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_m2m_update_work_period_payment}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodIdCreatedByM2M}}\",\r\n \"amount\": 450,\r\n \"status\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment 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 \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment 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 \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment 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_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment 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 invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with invalid workPeriodId 1", + "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(\"\\\"data.workPeriodId\\\" must be a valid GUID\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"aaa-bb-c\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with invalid workPeriodId 2", + "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(\"\\\"data.workPeriodId\\\" must be a string\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": 123,\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with invalid amount 1", + "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(\"\\\"data.amount\\\" must be a number\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": \"abc\",\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with invalid amount 2", + "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(\"\\\"data.amount\\\" must be greater than 0\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 0,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with invalid status 1", + "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(\"\\\"data.status\\\" must be one of [completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1200,\r\n \"status\": 123\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + }, + { + "name": "patch work period payment with invalid status 2", + "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(\"\\\"data.status\\\" must be one of [completed, cancelled]\")\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId}}\",\r\n \"amount\": 1200,\r\n \"status\": \"invalid-status\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Taas Teams", + "item": [ + { + "name": "GET /taas-teams", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams?perPage=10&page=1&name=*taas*&sortBy=lastActivityAt&sortOrder=desc", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams" + ], + "query": [ + { + "key": "perPage", + "value": "10" + }, + { + "key": "page", + "value": "1" + }, + { + "key": "name", + "value": "*taas*", + "description": "case-insensitive; support wildcard match" + }, + { + "key": "sortBy", + "value": "lastActivityAt", + "description": "allows: createdAt, updatedAt, lastActivityAt, id, status, name, type, best match" + }, + { + "key": "sortOrder", + "value": "desc", + "description": "allows: asc, desc" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams with booking manager", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams?perPage=10&page=1&name=*taas*&sortBy=lastActivityAt&sortOrder=desc", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams" + ], + "query": [ + { + "key": "perPage", + "value": "10" + }, + { + "key": "page", + "value": "1" + }, + { + "key": "name", + "value": "*taas*", + "description": "case-insensitive; support wildcard match" + }, + { + "key": "sortBy", + "value": "lastActivityAt", + "description": "allows: createdAt, updatedAt, lastActivityAt, id, status, name, type, best match" + }, + { + "key": "sortOrder", + "value": "desc", + "description": "allows: asc, desc" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams" + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/{{projectId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "{{projectId}}" + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id with booking manager", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:projectId", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":projectId" + ], + "variable": [ + { + "key": "projectId", + "value": "16705" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/{{projectId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "{{projectId}}" + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id/jobs/:jobId", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/{{projectId}}/jobs/{{jobId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "{{projectId}}", + "jobs", + "{{jobId}}" + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id/jobs/:jobId with booking manager", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_bookingManager}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:projectId/jobs/:jobId", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":projectId", + "jobs", + ":jobId" + ], + "variable": [ + { + "key": "projectId", + "value": "16705" + }, + { + "key": "jobId", + "value": "948a25a6-086f-4a96-aad5-9ccd2d3e87b2" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id/jobs/:jobId with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/{{projectId}}/jobs/{{jobId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "{{projectId}}", + "jobs", + "{{jobId}}" + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/skills", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_member}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/skills?perPage=10&page=1&orderBy=name", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "skills" + ], + "query": [ + { + "key": "perPage", + "value": "10" + }, + { + "key": "page", + "value": "1" + }, + { + "key": "orderBy", + "value": "name", + "description": "possible values are defined by /v5/skills" + } + ] + } + }, + "response": [] + }, + { + "name": "POST /taas-teams/email - team-issue-report", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_member}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"template\": \"team-issue-report\",\n \"data\": {\n \"projectName\": \"TaaS Project Name\",\n \"projectId\": 12345,\n \"reportText\": \"I have issue with ...\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/taas-teams/email", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "email" + ] + } + }, + "response": [] + }, + { + "name": "POST /taas-teams/email - member-issue-report", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"template\": \"member-issue-report\",\n \"data\": {\n \"projectName\": \"TaaS Project Name\",\n \"projectId\": 12345,\n \"userHandle\": \"pshah_manager\",\n \"reportText\": \"I have issue with ...\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/taas-teams/email", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "email" + ] + } + }, + "response": [] + }, + { + "name": "POST /taas-teams/email - extension-request", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"template\": \"extension-request\",\n \"data\": {\n \"projectName\": \"TaaS Project Name\",\n \"projectId\": 12345,\n \"userHandle\": \"pshah_manager\",\n \"reportText\": \"I would like to keep working with this member for 2 months...\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/taas-teams/email", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "email" + ] + } + }, + "response": [] + }, + { + "name": "POST /taas-teams/:id/members", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"handles\": [\n \"tester1234\",\n \"non-existing\"\n ],\n \"emails\": [\n \"non-existing@domain.com\",\n \"email@domain.com\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/taas-teams/:id/members", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":id", + "members" + ], + "variable": [ + { + "key": "id", + "value": "16705" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id/members", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:id/members?role=customer&fields=id,userId,role,createdAt,updatedAt,createdBy,updatedBy,handle,photoURL,workingHourStart,workingHourEnd,timeZone,email", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":id", + "members" + ], + "query": [ + { + "key": "role", + "value": "customer" + }, + { + "key": "fields", + "value": "id,userId,role,createdAt,updatedAt,createdBy,updatedBy,handle,photoURL,workingHourStart,workingHourEnd,timeZone,email" + } + ], + "variable": [ + { + "key": "id", + "value": "16705" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/:id/invites", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:id/invites?fields=createdAt,deletedAt,role,updatedBy,createdBy,id,projectId,userId,email,deletedBy,updatedAt,status", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":id", + "invites" + ], + "query": [ + { + "key": "fields", + "value": "createdAt,deletedAt,role,updatedBy,createdBy,id,projectId,userId,email,deletedBy,updatedAt,status" + } + ], + "variable": [ + { + "key": "id", + "value": "16705" + } + ] + } + }, + "response": [] + }, + { + "name": "DELETE /taas-teams/:id/members/:projectMemberId", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:id/members/:projectMemberId", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":id", + "members", + ":projectMemberId" + ], + "variable": [ + { + "key": "id", + "value": "16705" + }, + { + "key": "projectMemberId", + "value": "14327" + } + ] + } + }, + "response": [] + }, + { + "name": "GET /taas-teams/me", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/me", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "me" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "health check", + "item": [ + { + "name": "health check", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/health", + "host": [ + "{{URL}}" + ], + "path": [ + "health" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Create Demo Data For Team", + "item": [ + { + "name": "Get Users", + "item": [ + { + "name": "Get Users", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var demoUsers = 20;", + "", + "pm.test('We need to have at least ' + demoUsers + ' demo userIds. Define them in {{demoUserIdN}} variables.', function () {", + " for (var i = 0; i < demoUsers; i++) {", + " var variableName = \"demoUserId\" + (i + 1);", + " var existentValue = pm.variables.get(variableName);", + " var user = data[i];", + "", + " pm.expect(!!user || !!existentValue).to.be.true;", + "", + " postman.setEnvironmentVariable(variableName, user.id);", + " }", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{token_bookingManager}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://api.topcoder-dev.com/v5/users?perPage=20", + "protocol": "https", + "host": [ + "api", + "topcoder-dev", + "com" + ], + "path": [ + "v5", + "users" + ], + "query": [ + { + "key": "perPage", + "value": "20" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Create job #1 \"sourcing\"", + "item": [ + { + "name": "create job #1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId1\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job1\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 13,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"ee4c50c1-c8c3-475e-b6b6-edbd136a19d6\",\n \"89139c80-d0a2-47c2-aa16-14589d5afd10\",\n \"9f2d9127-6a2e-4506-ad76-c4ab63577b09\",\n \"9515e7ee-83b6-49d1-ba5c-6c59c5a8ef1b\",\n \"c854ab55-5922-4be1-8ecc-b3bc1f8629af\",\n \"8456002e-fa2d-44f0-b0e7-86b1c02b6e4c\",\n \"114b4ec8-805e-4c60-b351-14a955a991a9\",\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\",\n \"23839f38-6f19-4de9-9d28-f020056bca73\",\n \"289e42a3-23e9-49be-88e1-6deb93cd8c31\",\n \"b403f209-63b5-42bc-9b5f-1564416640d8\"\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 #2 \"in-review\"", + "item": [ + { + "name": "create job #2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId2\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job2\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\",\n \"23839f38-6f19-4de9-9d28-f020056bca73\",\n \"289e42a3-23e9-49be-88e1-6deb93cd8c31\",\n \"b403f209-63b5-42bc-9b5f-1564416640d8\"\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 #2 candidate 1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob1candidateId1\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId1}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob1candidateId2\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId2}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 3", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId3}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 4", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId4}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 5", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId5}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] }, { "name": "create job #2 candidate 6", @@ -5139,9 +12132,1156 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId6}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 7", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId7}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 8", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId8}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 9", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId9}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 10", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId10}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "update job #2 candidate 1 to \"shortlist\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{demoJob1candidateId1}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{demoJob1candidateId1}}" + ] + } + }, + "response": [] + }, + { + "name": "update job #2 candidate 2 to \"rejected\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"rejected\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{demoJob1candidateId2}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{demoJob1candidateId2}}" + ] + } + }, + "response": [] + }, + { + "name": "update job #2 status to \"in-review\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"in-review\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{demoJobId2}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{demoJobId2}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Create job #3 \"assigned\"", + "item": [ + { + "name": "create job #3", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId3\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job3\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [],\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 #3 candidate 11", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId11}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 12", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId12}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 13", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId13}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 14", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId14}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 15", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId15}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 16", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId16}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 17", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId17}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 18", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId18}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 19", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId19}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 20", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId20}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 11", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId11\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId11}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 12", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId12\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId12}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 13", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId13\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId13}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 14", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId14\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId14}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 15", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId15\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" ], "type": "text/javascript" } @@ -5158,7 +13298,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId6}}\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId15}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", "options": { "raw": { "language": "json" @@ -5166,27 +13306,47 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" ] } }, "response": [] }, { - "name": "create job #2 candidate 7", + "name": "create job 3 resource booking 16", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId16\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" ], "type": "text/javascript" } @@ -5203,7 +13363,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId7}}\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId16}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 800,\r\n \"customerRate\": 1000,\r\n \"rateType\": \"weekly\"\r\n}", "options": { "raw": { "language": "json" @@ -5211,27 +13371,47 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" ] } }, "response": [] }, { - "name": "create job #2 candidate 8", + "name": "create job 3 resource booking 17", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId17\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" ], "type": "text/javascript" } @@ -5248,7 +13428,114 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId8}}\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId17}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 2000,\r\n \"customerRate\": 2500,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 18", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId18\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId18}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2000-07-27T04:17:23.131Z\",\r\n \"endDate\": \"2000-09-27T04:17:23.131Z\",\r\n \"memberRate\": 3000,\r\n \"customerRate\": 3500,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 19", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId19\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId19}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2022-07-27T04:17:23.131Z\",\r\n \"endDate\": \"2022-09-27T04:17:23.131Z\",\r\n \"memberRate\": 1700,\r\n \"customerRate\": 1900,\r\n \"rateType\": \"weekly\"\r\n}", "options": { "raw": { "language": "json" @@ -5256,27 +13543,47 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" ] } }, "response": [] }, { - "name": "create job #2 candidate 9", + "name": "create job 3 resource booking 20", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId20\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" ], "type": "text/javascript" } @@ -5293,7 +13600,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId9}}\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId20}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 0,\r\n \"customerRate\": 0,\r\n \"rateType\": \"weekly\"\r\n}", "options": { "raw": { "language": "json" @@ -5301,25 +13608,25 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" ] } }, "response": [] }, { - "name": "create job #2 candidate 10", + "name": "update job 3 resource booking 11 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5328,7 +13635,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5338,7 +13645,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId10}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5346,19 +13653,20 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId11}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings", + "{{demoJob3resourceCandiateId11}}" ] } }, "response": [] }, { - "name": "update job #2 candidate 1 to \"shortlist\"", + "name": "update job 3 resource booking 12 status to \"in-review\"", "event": [ { "listen": "test", @@ -5383,7 +13691,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "raw": "{\r\n \"status\": \"in-review\"\r\n}", "options": { "raw": { "language": "json" @@ -5391,20 +13699,20 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{demoJob1candidateId1}}", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId12}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{demoJob1candidateId1}}" + "resourceBookings", + "{{demoJob3resourceCandiateId12}}" ] } }, "response": [] }, { - "name": "update job #2 candidate 2 to \"rejected\"", + "name": "update job 3 resource booking 13 status to \"closed\"", "event": [ { "listen": "test", @@ -5429,7 +13737,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"rejected\"\r\n}", + "raw": "{\r\n \"status\": \"closed\"\r\n}", "options": { "raw": { "language": "json" @@ -5437,20 +13745,20 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{demoJob1candidateId2}}", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId13}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{demoJob1candidateId2}}" + "resourceBookings", + "{{demoJob3resourceCandiateId13}}" ] } }, "response": [] }, { - "name": "update job #2 status to \"in-review\"", + "name": "update job 3 resource booking 14 status to \"cancelled\"", "event": [ { "listen": "test", @@ -5475,7 +13783,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"in-review\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\"\r\n}", "options": { "raw": { "language": "json" @@ -5483,44 +13791,35 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{demoJobId2}}", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId14}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{demoJobId2}}" + "resourceBookings", + "{{demoJob3resourceCandiateId14}}" ] } }, "response": [] - } - ] - }, - { - "name": "Create job #3 \"assigned\"", - "item": [ + }, { - "name": "create job #3", + "name": "update job 3 resource booking 15 status to \"sourcing\"", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJobId3\",data.id);" + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" ], "type": "text/javascript" } } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5530,7 +13829,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job3\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [],\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "raw": "{\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -5538,25 +13837,26 @@ } }, "url": { - "raw": "{{URL}}/jobs", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId15}}", "host": [ "{{URL}}" ], "path": [ - "jobs" + "resourceBookings", + "{{demoJob3resourceCandiateId15}}" ] } }, "response": [] }, { - "name": "create job #3 candidate 11", + "name": "update job 3 resource booking 16 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5565,7 +13865,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5575,7 +13875,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId11}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5583,25 +13883,26 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId16}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings", + "{{demoJob3resourceCandiateId16}}" ] } }, "response": [] }, { - "name": "create job #3 candidate 12", + "name": "update job 3 resource booking 17 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5610,7 +13911,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5620,7 +13921,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId12}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5628,25 +13929,26 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId17}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings", + "{{demoJob3resourceCandiateId17}}" ] } }, "response": [] }, { - "name": "create job #3 candidate 13", + "name": "update job 3 resource booking 18 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5655,7 +13957,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5665,7 +13967,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId13}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5673,25 +13975,26 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId18}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings", + "{{demoJob3resourceCandiateId18}}" ] } }, "response": [] }, { - "name": "create job #3 candidate 14", + "name": "update job 3 resource booking 19 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5700,7 +14003,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5710,7 +14013,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId14}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5718,25 +14021,26 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId19}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings", + "{{demoJob3resourceCandiateId19}}" ] } }, "response": [] }, { - "name": "create job #3 candidate 15", + "name": "update job 3 resource booking 20 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5745,7 +14049,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5755,7 +14059,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId15}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5763,25 +14067,26 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId20}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings", + "{{demoJob3resourceCandiateId20}}" ] } }, "response": [] }, { - "name": "create job #3 candidate 16", + "name": "update job #3 status to \"assigned\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5790,7 +14095,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5800,7 +14105,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId16}}\"\r\n}", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", "options": { "raw": { "language": "json" @@ -5808,27 +14113,37 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/jobs/{{demoJobId3}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "jobs", + "{{demoJobId3}}" ] } }, "response": [] - }, + } + ] + }, + { + "name": "Create job #4 \"closed\"", + "item": [ { - "name": "create job #3 candidate 17", + "name": "create job #4", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId4\",data.id);" ], "type": "text/javascript" } @@ -5845,7 +14160,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId17}}\"\r\n}", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job4\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"8456002e-fa2d-44f0-b0e7-86b1c02b6e4c\",\n \"114b4ec8-805e-4c60-b351-14a955a991a9\",\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", "options": { "raw": { "language": "json" @@ -5853,25 +14168,25 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/jobs", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "jobs" ] } }, "response": [] }, { - "name": "create job #3 candidate 18", + "name": "update job #4 status to \"closed\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5880,7 +14195,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5890,7 +14205,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId18}}\"\r\n}", + "raw": "{\r\n \"status\": \"closed\"\r\n}", "options": { "raw": { "language": "json" @@ -5898,27 +14213,37 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/jobs/{{demoJobId4}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "jobs", + "{{demoJobId4}}" ] } }, "response": [] - }, + } + ] + }, + { + "name": "Create job #5 \"cancelled\"", + "item": [ { - "name": "create job #3 candidate 19", + "name": "create job #5", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId5\",data.id);" ], "type": "text/javascript" } @@ -5935,7 +14260,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId19}}\"\r\n}", + "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job5\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", "options": { "raw": { "language": "json" @@ -5943,25 +14268,25 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/jobs", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "jobs" ] } }, "response": [] }, { - "name": "create job #3 candidate 20", + "name": "update job #5 status to \"cancelled\"", "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Successful POST request\", function () {", + "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", "});" ], @@ -5970,7 +14295,7 @@ } ], "request": { - "method": "POST", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -5980,1380 +14305,1986 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId20}}\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\"\r\n}", "options": { "raw": { "language": "json" } - } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{demoJobId5}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{demoJobId5}}" + ] + } + }, + "response": [] + } + ] + } + ] + }, + { + "name": "Test Permission Rules", + "item": [ + { + "name": "Request with Administrator Role", + "item": [ + { + "name": "Jobs", + "item": [ + { + "name": "✔ create job with administrator", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"job_id_created_by_administrator\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "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": "✔ get job with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_administrator}}" + ] + } + }, + "response": [] + }, + { + "name": "✔ search jobs with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ], + "query": [ + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "perPage", + "value": "3", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "projectId", + "value": "21", + "disabled": true + }, + { + "key": "externalId", + "value": "1212", + "disabled": true + }, + { + "key": "description", + "value": "Dummy", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "resourceType", + "value": "Dummy Resource Type", + "disabled": true + }, + { + "key": "skill", + "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + }, + { + "key": "workload", + "value": "full-time", + "disabled": true + }, + { + "key": "title", + "value": "dummy", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "✔ put job with administrator", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_administrator}}" + ] + } + }, + "response": [] + }, + { + "name": "✔ patch job with administrator", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_administrator}}" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] + { + "name": "✔ delete job with administrator", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_administrator}}" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "create job 3 resource booking 11", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId11\",data.id);" - ], - "type": "text/javascript" - } - }, + "name": "Job Candidates", + "item": [ { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + "name": "✔ create job candidate with administrator", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"job_candidate_id_created_by_administrator\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId11}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{job_id_created_by_administrator}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 12", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId12\",data.id);" + "name": "✔ get job candidate with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } + "url": { + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{job_candidate_id_created_by_administrator}}" + ] + } + }, + "response": [] }, { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + "name": "✔ search job candidates with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId12}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "1", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "jobId", + "value": "46225f4c-c2a3-4603-a141-0277e96fabfa", + "disabled": true + }, + { + "key": "userId", + "value": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "disabled": true + }, + { + "key": "status", + "value": "shortlist", + "disabled": true + } + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 13", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId13\",data.id);" + "name": "✔ put job candidate with administrator", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } + "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}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{job_candidate_id_created_by_administrator}}" + ] + } + }, + "response": [] }, { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + "name": "✔ patch job candidate with administrator", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId13}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{job_candidate_id_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] + { + "name": "✔ delete job candidate with administrator", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{job_candidate_id_created_by_administrator}}" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "create job 3 resource booking 14", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId14\",data.id);" - ], - "type": "text/javascript" - } - }, + "name": "Resource Bookings", + "item": [ { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId14}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "Before Test", + "item": [ + { + "name": "✔ create job with administrator", + "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(\"job_id_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "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": [] } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 15", - "event": [ + }, { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId15\",data.id);" + "name": "✔ create resource booking with administrator", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"resource_bookings_id_created_by_administrator\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } + "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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] }, { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + "name": "✔ get resource booking with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId15}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resource_bookings_id_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 16", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId16\",data.id);" + "name": "✔ search resource bookings with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } + "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-27", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + }, + { + "key": "projectIds", + "value": "111, 16705", + "disabled": true + } + ] + } + }, + "response": [] }, { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId16}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 800,\r\n \"customerRate\": 1000,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "✔ put resource booking with administrator", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "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}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resource_bookings_id_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 17", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId17\",data.id);" + "name": "✔ patch resource booking with administrator", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } + "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}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resource_bookings_id_created_by_administrator}}" + ] + } + }, + "response": [] }, { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + "name": "✔ delete resource booking with administrator", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId17}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 2000,\r\n \"customerRate\": 2500,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resource_bookings_id_created_by_administrator}}" + ] } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "create job 3 resource booking 18", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId18\",data.id);" - ], - "type": "text/javascript" - } - }, + "name": "Work Periods", + "item": [ { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId18}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2000-07-27T04:17:23.131Z\",\r\n \"endDate\": \"2000-09-27T04:17:23.131Z\",\r\n \"memberRate\": 3000,\r\n \"customerRate\": 3500,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "Before Test", + "item": [ + { + "name": "✔ create job with administrator", + "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(\"job_id_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "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 administrator", + "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(\"resource_bookings_id_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] } - } + ] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" + { + "name": "✔ create work period with administrator", + "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(\"workPeriodId_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 19", - "event": [ + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_bookings_id_created_by_administrator}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId19\",data.id);" + "name": "✔ get work period with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId19}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2022-07-27T04:17:23.131Z\",\r\n \"endDate\": \"2022-09-27T04:17:23.131Z\",\r\n \"memberRate\": 1700,\r\n \"customerRate\": 1900,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "create job 3 resource booking 20", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId20\",data.id);" + "name": "✔ search work periods with administrator", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ], + "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": "resourceBookingId", + "value": "{{resource_bookings_id_created_by_administrator}}", + "disabled": true + }, + { + "key": "resourceBookingIds", + "value": "{{resource_bookings_id_created_by_administrator}},{{resource_bookings_id_created_by_administrator}}", + "disabled": true + }, + { + "key": "paymentStatus", + "value": "pending", + "disabled": true + }, + { + "key": "startDate", + "value": "2021-03-07", + "disabled": true + }, + { + "key": "endDate", + "value": "2021-03-13", + "disabled": true + }, + { + "key": "userHandle", + "value": "pshah_manager", + "disabled": true + }, + { + "key": "projectId", + "value": "111", + "disabled": true + } + ] + } + }, + "response": [] }, { - "listen": "prerequest", - "script": { - "exec": [ - "const startDate = new Date()", - "startDate.setDate(startDate.getDate() - 3);", - "", - "const endDate = new Date()", - "endDate.setDate(endDate.getDate() + 3);", - "", - "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", - "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + "name": "✔ put work period with administrator", + "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_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId20}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 0,\r\n \"customerRate\": 0,\r\n \"rateType\": \"weekly\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_bookings_id_created_by_administrator}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings" - ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 11 status to \"assigned\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ patch work period with administrator", + "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_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_bookings_id_created_by_administrator}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId11}}", - "host": [ - "{{URL}}" + { + "name": "✔ delete work period with administrator", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 204', function () {\r", + " pm.response.to.have.status(204);\r", + "});" + ], + "type": "text/javascript" + } + } ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId11}}" - ] + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods/{{workPeriodId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods", + "{{workPeriodId_created_by_administrator}}" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "update job 3 resource booking 12 status to \"in-review\"", - "event": [ + "name": "Work Period Payments", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"in-review\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "Before Test", + "item": [ + { + "name": "✔ create job with administrator", + "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(\"job_id_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_17234}},\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 administrator", + "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(\"resource_bookings_id_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{project_id_17234}},\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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "✔ create work period with administrator", + "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(\"workPeriodId_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_bookings_id_created_by_administrator}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId12}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId12}}" ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 13 status to \"closed\"", - "event": [ + }, { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ create work period payment with administrator", + "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(\"workPeriodPaymentId_created_by_administrator\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"closed\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_by_administrator}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId13}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId13}}" - ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 14 status to \"cancelled\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ get work period payment with administrator", + "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_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId14}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId14}}" - ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 15 status to \"sourcing\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ search work period payments with administrator", + "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_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"sourcing\"\r\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "status", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "workPeriodId", + "value": "{{workPeriodId_created_by_administrator}}", + "disabled": true + }, + { + "key": "workPeriodIds", + "value": "{{workPeriodId_created_by_administrator}},{{workPeriodId_created_by_administrator}}", + "disabled": true + }, + { + "key": "status", + "value": "completed", + "disabled": true + } + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId15}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId15}}" - ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 16 status to \"assigned\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "✔ put work period payment with administrator", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId16}}", - "host": [ - "{{URL}}" ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId16}}" - ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 17 status to \"assigned\"", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_by_administrator}}\",\r\n \"amount\": 1600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId_created_by_administrator}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId17}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId17}}" - ] - } - }, - "response": [] - }, - { - "name": "update job 3 resource booking 18 status to \"assigned\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "✔ patch work period payment with administrator", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test('Status code is 200', function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript" + } } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId18}}", - "host": [ - "{{URL}}" ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId18}}" - ] + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_by_administrator}}\",\r\n \"amount\": 450,\r\n \"status\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_by_administrator}}", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments", + "{{workPeriodPaymentId_created_by_administrator}}" + ] + } + }, + "response": [] } - }, - "response": [] - }, + ] + } + ] + }, + { + "name": "Request with Topcoder User Role", + "item": [ { - "name": "update job 3 resource booking 19 status to \"assigned\"", - "event": [ + "name": "README", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "name": "[STUB] all operations cause 403 error if user is not member of project", + "request": { + "method": "LOCK", + "header": [], + "url": { + "raw": "" } - } - }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId19}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId19}}" - ] + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "update job 3 resource booking 20 status to \"assigned\"", - "event": [ + "name": "Jobs", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ create job with member", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"job_id_created_by_member\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_member_tester1234}}", + "type": "text" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_16718}},\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": [] }, - "url": { - "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId20}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{demoJob3resourceCandiateId20}}" - ] - } - }, - "response": [] - }, - { - "name": "update job #3 status to \"assigned\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ get job with member", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member_tester1234}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"assigned\"\r\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_member}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/jobs/{{demoJobId3}}", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs", - "{{demoJobId3}}" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Create job #4 \"closed\"", - "item": [ - { - "name": "create job #4", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJobId4\",data.id);" + "name": "✔ search jobs with member filtering by \"projectId\"", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member_tester1234}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job4\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"8456002e-fa2d-44f0-b0e7-86b1c02b6e4c\",\n \"114b4ec8-805e-4c60-b351-14a955a991a9\",\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "{{URL}}/jobs?projectId={{project_id_16718}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ], + "query": [ + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "perPage", + "value": "3", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "projectId", + "value": "{{project_id_16718}}" + }, + { + "key": "externalId", + "value": "1212", + "disabled": true + }, + { + "key": "description", + "value": "Dummy", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "resourceType", + "value": "Dummy Resource Type", + "disabled": true + }, + { + "key": "skill", + "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + }, + { + "key": "workload", + "value": "full-time", + "disabled": true + }, + { + "key": "title", + "value": "dummy", + "disabled": true + } + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/jobs", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs" - ] - } - }, - "response": [] - }, - { - "name": "update job #4 status to \"closed\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✔ put job with member", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member_tester1234}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"closed\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_16718}},\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_member}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/jobs/{{demoJobId4}}", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs", - "{{demoJobId4}}" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Create job #5 \"cancelled\"", - "item": [ - { - "name": "create job #5", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "\r", - "pm.test(\"Successful POST request\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", - "});\r", - "\r", - "postman.setEnvironmentVariable(\"demoJobId5\",data.id);" + "name": "✔ patch job with member", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member_tester1234}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"projectId\": {{projectId}},\n \"externalId\": \"0\",\n \"description\": \"taas-demo-job5\",\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\n \"duration\": 1,\n \"numPositions\": 7,\n \"resourceType\": \"Dummy Resource Type\",\n \"rateType\": \"weekly\",\n \"workload\": \"full-time\",\n \"skills\": [\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\n \"6388a632-c3ad-4525-9a73-66a527c03672\"\n ],\n \"title\": \"Dummy title - at most 64 characters\"\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "{\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_member}}" + ] } - } + }, + "response": [] }, - "url": { - "raw": "{{URL}}/jobs", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs" - ] - } - }, - "response": [] - }, - { - "name": "update job #5 status to \"cancelled\"", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Successful PATCH request\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", - "});" + "name": "✘ delete job with member", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member_tester1234}}" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_bookingManager}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", - "options": { - "raw": { - "language": "json" + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{job_id_created_by_member}}" + ] } - } - }, - "url": { - "raw": "{{URL}}/jobs/{{demoJobId5}}", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs", - "{{demoJobId5}}" - ] + }, + "response": [] } - }, - "response": [] - } - ] - } - ] - }, - { - "name": "Test Permission Rules", - "item": [ - { - "name": "Request with Administrator Role", - "item": [ + ] + }, { - "name": "Jobs", + "name": "Job Candidates", "item": [ { - "name": "✔ create job with administrator", + "name": "Before Test", + "item": [ + { + "name": "create job candidate", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"job_candidate_id_created_for_member\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "✘ create job candidate with member", "event": [ { "listen": "test", "script": { "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_id_created_by_administrator\",data.id);" + "postman.setEnvironmentVariable(\"job_candidate_id_created_by_member\",data.id);" ], "type": "text/javascript" } @@ -7364,13 +16295,13 @@ "header": [ { "key": "Authorization", - "value": "Bearer {{token_administrator}}", - "type": "text" + "type": "text", + "value": "Bearer {{token_member_tester1234}}" } ], "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}", + "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", "options": { "raw": { "language": "json" @@ -7378,69 +16309,69 @@ } }, "url": { - "raw": "{{URL}}/jobs", + "raw": "{{URL}}/jobCandidates", "host": [ "{{URL}}" ], "path": [ - "jobs" + "jobCandidates" ] } }, "response": [] }, { - "name": "✔ get job with administrator", + "name": "✔ get job candidate with member", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_administrator}}" + "jobCandidates", + "{{job_candidate_id_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ search jobs with administrator", + "name": "✔ search job candidates with member filtering by \"jobId\"", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "url": { - "raw": "{{URL}}/jobs", + "raw": "{{URL}}/jobCandidates?jobId={{job_id_created_by_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs" + "jobCandidates" ], "query": [ { "key": "page", - "value": "0", + "value": "1", "disabled": true }, { "key": "perPage", - "value": "3", + "value": "1", "disabled": true }, { @@ -7454,53 +16385,17 @@ "disabled": true }, { - "key": "projectId", - "value": "21", - "disabled": true - }, - { - "key": "externalId", - "value": "1212", - "disabled": true - }, - { - "key": "description", - "value": "Dummy", - "disabled": true - }, - { - "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", - "disabled": true - }, - { - "key": "resourceType", - "value": "Dummy Resource Type", - "disabled": true - }, - { - "key": "skill", - "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "disabled": true + "key": "jobId", + "value": "{{job_id_created_by_member}}" }, { - "key": "rateType", - "value": "hourly", + "key": "userId", + "value": "fe38eed1-af73-41fd-85a2-ac4da1ff09a3", "disabled": true }, { "key": "status", - "value": "sourcing", - "disabled": true - }, - { - "key": "workload", - "value": "full-time", - "disabled": true - }, - { - "key": "title", - "value": "dummy", + "value": "shortlist", "disabled": true } ] @@ -7509,19 +16404,19 @@ "response": [] }, { - "name": "✔ put job with administrator", + "name": "✔ put job candidate with member", "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"status\": \"selected\"\r\n}", "options": { "raw": { "language": "json" @@ -7529,32 +16424,32 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_administrator}}" + "jobCandidates", + "{{job_candidate_id_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ patch job with administrator", + "name": "✔ patch job candidate with member", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "body": { "mode": "raw", - "raw": "{\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "raw": "{\r\n \"status\": \"shortlist\"\r\n}", "options": { "raw": { "language": "json" @@ -7562,27 +16457,27 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_administrator}}" + "jobCandidates", + "{{job_candidate_id_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ delete job with administrator", + "name": "✘ delete job candidate with member", "request": { "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "body": { @@ -7592,35 +16487,128 @@ "raw": { "language": "json" } - } - }, - "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_administrator}}", - "host": [ - "{{URL}}" + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{job_candidate_id_created_for_member}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Resource Bookings", + "item": [ + { + "name": "Before Test", + "item": [ + { + "name": "create job", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"job_id_created_by_member\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_member_tester1234}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_16718}},\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", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"resource_booking_id_created_for_member\",data.id);" + ], + "type": "text/javascript" + } + } ], - "path": [ - "jobs", - "{{job_id_created_by_administrator}}" - ] + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] } - }, - "response": [] - } - ] - }, - { - "name": "Job Candidates", - "item": [ + ] + }, { - "name": "✔ create job candidate with administrator", + "name": "✘ create resource booking with member", "event": [ { "listen": "test", "script": { "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_candidate_id_created_by_administrator\",data.id);" + "postman.setEnvironmentVariable(\"resource_booking_id_created_by_member\",data.id);" ], "type": "text/javascript" } @@ -7632,12 +16620,12 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{job_id_created_by_administrator}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\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 \"billingAccountId\": 80000071\r\n}", "options": { "raw": { "language": "json" @@ -7645,59 +16633,59 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" ] } }, "response": [] }, { - "name": "✔ get job candidate with administrator", + "name": "✔ get resource booking with member", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_by_administrator}}" + "resourceBookings", + "{{resource_booking_id_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ search job candidates with administrator", + "name": "✔ search resource bookings with member filtering by \"projectId\"", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings?projectId={{project_id_16718}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" ], "query": [ { @@ -7707,7 +16695,7 @@ }, { "key": "perPage", - "value": "1", + "value": "5", "disabled": true }, { @@ -7717,23 +16705,37 @@ }, { "key": "sortOrder", - "value": "asc", + "value": "desc", "disabled": true }, { - "key": "jobId", - "value": "46225f4c-c2a3-4603-a141-0277e96fabfa", + "key": "startDate", + "value": "2020-09-27", "disabled": true }, { - "key": "userId", - "value": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "key": "endDate", + "value": "2020-09-27", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", "disabled": true }, { "key": "status", - "value": "shortlist", + "value": "sourcing", + "disabled": true + }, + { + "key": "projectIds", + "value": "111, 16705", "disabled": true + }, + { + "key": "projectId", + "value": "{{project_id_16718}}" } ] } @@ -7741,19 +16743,19 @@ "response": [] }, { - "name": "✔ put job candidate with administrator", + "name": "✘ put resource booking with member", "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "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 \"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}", "options": { "raw": { "language": "json" @@ -7761,32 +16763,32 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_by_administrator}}" + "resourceBookings", + "{{resource_booking_id_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ patch job candidate with administrator", + "name": "✘ patch resource booking with member", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "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}", "options": { "raw": { "language": "json" @@ -7794,27 +16796,27 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_by_administrator}}" + "resourceBookings", + "{{resource_booking_id_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ delete job candidate with administrator", + "name": "✘ delete resource booking with member", "request": { "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "body": { @@ -7827,13 +16829,13 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_by_administrator}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_by_administrator}}" + "resourceBookings", + "{{resource_booking_id_created_for_member}}" ] } }, @@ -7842,17 +16844,172 @@ ] }, { - "name": "Resource Bookings", + "name": "Work Periods", "item": [ { - "name": "✔ create resource booking with administrator", + "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(\"job_id_created_by_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_member_tester1234}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_16718}},\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", + "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(\"resource_booking_id_created_for_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create work period", + "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(\"workPeriodId_created_for_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_booking_id_created_for_member}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "✘ create work period with member", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resource_bookings_id_created_by_administrator\",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" } @@ -7864,12 +17021,12 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "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-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 \"resourceBookingId\": \"{{resource_booking_id_created_for_member}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -7877,59 +17034,65 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "work-periods" ] } }, "response": [] }, { - "name": "✔ get resource booking with administrator", + "name": "✔ get work period with member", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "url": { - "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}?projectId=16718", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_bookings_id_created_by_administrator}}" + "work-periods", + "{{workPeriodId_created_for_member}}" + ], + "query": [ + { + "key": "projectId", + "value": "16718" + } ] } }, "response": [] }, { - "name": "✔ search resource bookings with administrator", + "name": "✔ search work periods with member", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/work-periods?projectId=16718", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "work-periods" ], "query": [ { @@ -7953,29 +17116,38 @@ "disabled": true }, { - "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "key": "resourceBookingId", + "value": "{{resource_booking_id_created_for_member}}", "disabled": true }, { - "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "key": "resourceBookingIds", + "value": "{{resource_booking_id_created_for_member}},{{resource_booking_id_created_for_member}}", "disabled": true }, { - "key": "rateType", - "value": "hourly", + "key": "paymentStatus", + "value": "pending", "disabled": true }, { - "key": "status", - "value": "sourcing", + "key": "startDate", + "value": "2021-03-07", "disabled": true }, { - "key": "projectIds", - "value": "111, 16705", + "key": "endDate", + "value": "2021-03-13", + "disabled": true + }, + { + "key": "userHandle", + "value": "pshah_manager", "disabled": true + }, + { + "key": "projectId", + "value": "16718" } ] } @@ -7983,19 +17155,34 @@ "response": [] }, { - "name": "✔ put resource booking with administrator", + "name": "✘ put work period 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_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "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-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 \"resourceBookingId\": \"{{resource_booking_id_created_for_member}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -8003,32 +17190,47 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_bookings_id_created_by_administrator}}" + "work-periods", + "{{workPeriodId_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ patch resource booking with administrator", + "name": "✘ patch work period 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_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "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 \"resourceBookingId\": \"{{resource_booking_id_created_for_member}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -8036,27 +17238,42 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_bookings_id_created_by_administrator}}" + "work-periods", + "{{workPeriodId_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ delete resource booking with administrator", + "name": "✘ delete work period 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": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_administrator}}" + "value": "Bearer {{token_member_tester1234}}" } ], "body": { @@ -8069,53 +17286,236 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_bookings_id_created_by_administrator}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_bookings_id_created_by_administrator}}" + "work-periods", + "{{workPeriodId_created_for_member}}" ] } }, "response": [] } ] - } - ] - }, - { - "name": "Request with Topcoder User Role", - "item": [ + }, { - "name": "README", + "name": "Work Period Payments", "item": [ { - "name": "[STUB] all operations cause 403 error if user is not member of project", - "request": { - "method": "LOCK", - "header": [], - "url": { - "raw": "" + "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(\"job_id_created_for_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_17234}},\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", + "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(\"resource_bookings_id_created_for_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{project_id_17234}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{job_id_created_for_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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "✔ create work period", + "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(\"workPeriodId_created_for_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_bookings_id_created_for_member}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "✔ create work period payment", + "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(\"workPeriodPaymentId_created_for_member\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_for_member}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] } - }, - "response": [] - } - ] - }, - { - "name": "Jobs", - "item": [ + ] + }, { - "name": "✔ create job with member", + "name": "✘ create work period payment with member", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_id_created_by_member\",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" } @@ -8126,13 +17526,13 @@ "header": [ { "key": "Authorization", - "value": "Bearer {{token_member_tester1234}}", - "type": "text" + "type": "text", + "value": "Bearer {{token_member_tester1234}}" } ], "body": { "mode": "raw", - "raw": "{\n \"projectId\": {{project_id_16718}},\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}", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_for_member}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", "options": { "raw": { "language": "json" @@ -8140,19 +17540,34 @@ } }, "url": { - "raw": "{{URL}}/jobs", + "raw": "{{URL}}/work-period-payments", "host": [ "{{URL}}" ], "path": [ - "jobs" + "work-period-payments" ] } }, "response": [] }, { - "name": "✔ get job with member", + "name": "✘ get work period payment 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": "GET", "header": [ @@ -8163,20 +17578,35 @@ } ], "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_member}}" + "work-period-payments", + "{{workPeriodPaymentId_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ search jobs with member filtering by \"projectId\"", + "name": "✘ search work period payments 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": "GET", "header": [ @@ -8187,81 +17617,47 @@ } ], "url": { - "raw": "{{URL}}/jobs?projectId={{project_id_16718}}", + "raw": "{{URL}}/work-period-payments", "host": [ "{{URL}}" ], "path": [ - "jobs" + "work-period-payments" ], "query": [ { "key": "page", - "value": "0", + "value": "1", "disabled": true }, { "key": "perPage", - "value": "3", + "value": "5", "disabled": true }, { "key": "sortBy", - "value": "id", + "value": "status", "disabled": true }, { "key": "sortOrder", - "value": "asc", - "disabled": true - }, - { - "key": "projectId", - "value": "{{project_id_16718}}" - }, - { - "key": "externalId", - "value": "1212", - "disabled": true - }, - { - "key": "description", - "value": "Dummy", - "disabled": true - }, - { - "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", - "disabled": true - }, - { - "key": "resourceType", - "value": "Dummy Resource Type", + "value": "desc", "disabled": true }, { - "key": "skill", - "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "key": "workPeriodId", + "value": "{{workPeriodPaymentId_created_for_member}}", "disabled": true }, { - "key": "rateType", - "value": "hourly", + "key": "workPeriodIds", + "value": "{{workPeriodPaymentId_created_for_member}},{{workPeriodPaymentId_created_for_member}}", "disabled": true }, { "key": "status", - "value": "sourcing", - "disabled": true - }, - { - "key": "workload", - "value": "full-time", - "disabled": true - }, - { - "key": "title", - "value": "dummy", + "value": "completed", "disabled": true } ] @@ -8270,7 +17666,22 @@ "response": [] }, { - "name": "✔ put job with member", + "name": "✘ put work period payment 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": [ @@ -8282,7 +17693,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"projectId\": {{project_id_16718}},\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_for_member}}\",\r\n \"amount\": 1600,\r\n \"status\": \"completed\"\r\n}", "options": { "raw": { "language": "json" @@ -8290,20 +17701,35 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_member}}" + "work-period-payments", + "{{workPeriodPaymentId_created_for_member}}" ] } }, "response": [] }, { - "name": "✔ patch job with member", + "name": "✘ patch work period payment 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": [ @@ -8315,7 +17741,7 @@ ], "body": { "mode": "raw", - "raw": "{\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_for_member}}\",\r\n \"amount\": 450,\r\n \"status\": \"cancelled\"\r\n}", "options": { "raw": { "language": "json" @@ -8323,47 +17749,35 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_for_member}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_member}}" + "work-period-payments", + "{{workPeriodPaymentId_created_for_member}}" ] } }, "response": [] - }, + } + ] + } + ] + }, + { + "name": "Request with Connect Manager Role", + "item": [ + { + "name": "README", + "item": [ { - "name": "✘ delete job with member", + "name": "[STUB] all operations except get/search cause 403 error if manager is not member of project", "request": { - "method": "DELETE", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_member_tester1234}}" - } - ], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, + "method": "LOCK", + "header": [], "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_member}}", - "host": [ - "{{URL}}" - ], - "path": [ - "jobs", - "{{job_id_created_by_member}}" - ] + "raw": "" } }, "response": [] @@ -8371,66 +17785,17 @@ ] }, { - "name": "Job Candidates", + "name": "Jobs", "item": [ { - "name": "Before Test", - "item": [ - { - "name": "create job candidate", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_candidate_id_created_for_member\",data.id);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_administrator}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{URL}}/jobCandidates", - "host": [ - "{{URL}}" - ], - "path": [ - "jobCandidates" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "✘ create job candidate with member", + "name": "✔ create job with connect manager", "event": [ { "listen": "test", "script": { "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_candidate_id_created_by_member\",data.id);" + "postman.setEnvironmentVariable(\"job_id_created_by_connect_manager\",data.id);" ], "type": "text/javascript" } @@ -8441,13 +17806,13 @@ "header": [ { "key": "Authorization", - "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}", + "type": "text" } ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{job_id_created_by_member}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", + "raw": "{\n \"projectId\": {{project_id_16843}},\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" @@ -8455,69 +17820,69 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/jobs", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "jobs" ] } }, "response": [] }, { - "name": "✔ get job candidate with member", + "name": "✔ get job with connect manager", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", + "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_member}}" + "jobs", + "{{job_id_created_by_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ search job candidates with member filtering by \"jobId\"", + "name": "✔ search jobs with connect manager", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "url": { - "raw": "{{URL}}/jobCandidates?jobId={{job_id_created_by_member}}", + "raw": "{{URL}}/jobs", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "jobs" ], "query": [ { "key": "page", - "value": "1", + "value": "0", "disabled": true }, { "key": "perPage", - "value": "1", + "value": "3", "disabled": true }, { @@ -8531,17 +17896,53 @@ "disabled": true }, { - "key": "jobId", - "value": "{{job_id_created_by_member}}" + "key": "projectId", + "value": "21", + "disabled": true }, { - "key": "userId", - "value": "fe38eed1-af73-41fd-85a2-ac4da1ff09a3", + "key": "externalId", + "value": "1212", + "disabled": true + }, + { + "key": "description", + "value": "Dummy", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "resourceType", + "value": "Dummy Resource Type", + "disabled": true + }, + { + "key": "skill", + "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", "disabled": true }, { "key": "status", - "value": "shortlist", + "value": "sourcing", + "disabled": true + }, + { + "key": "workload", + "value": "full-time", + "disabled": true + }, + { + "key": "title", + "value": "dummy", "disabled": true } ] @@ -8550,19 +17951,19 @@ "response": [] }, { - "name": "✔ put job candidate with member", + "name": "✔ put job with connect manager", "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "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": "{\n \"projectId\": {{project_id_16843}},\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", "options": { "raw": { "language": "json" @@ -8570,32 +17971,32 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", + "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_member}}" + "jobs", + "{{job_id_created_by_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ patch job candidate with member", + "name": "✔ patch job with connect manager", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "raw": "{\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", "options": { "raw": { "language": "json" @@ -8603,27 +18004,27 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", + "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_member}}" + "jobs", + "{{job_id_created_by_connect_manager}}" ] } }, "response": [] }, { - "name": "✘ delete job candidate with member", + "name": "✘ delete job with connect manager", "request": { "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "body": { @@ -8636,13 +18037,13 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_member}}", + "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_member}}" + "jobs", + "{{job_id_created_by_connect_manager}}" ] } }, @@ -8651,20 +18052,20 @@ ] }, { - "name": "Resource Bookings", + "name": "Job Candidates", "item": [ { "name": "Before Test", "item": [ { - "name": "create resource booking", + "name": "create job candidate", "event": [ { "listen": "test", "script": { "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resource_booking_id_created_for_member\",data.id);" + "postman.setEnvironmentVariable(\"job_candidate_id_created_for_connect_manager\",data.id);" ], "type": "text/javascript" } @@ -8681,7 +18082,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-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 \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", "options": { "raw": { "language": "json" @@ -8689,12 +18090,12 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/jobCandidates", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "jobCandidates" ] } }, @@ -8703,14 +18104,14 @@ ] }, { - "name": "✘ create resource booking with member", + "name": "✘ create job candidate with connect manager", "event": [ { "listen": "test", "script": { "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resource_booking_id_created_by_member\",data.id);" + "postman.setEnvironmentVariable(\"job_candidate_id_created_by_connect_manager\",data.id);" ], "type": "text/javascript" } @@ -8722,12 +18123,12 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "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-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 \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", "options": { "raw": { "language": "json" @@ -8735,59 +18136,59 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/jobCandidates", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "jobCandidates" ] } }, "response": [] }, { - "name": "✔ get resource booking with member", + "name": "✔ get job candidate with connect manager", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_member}}" + "jobCandidates", + "{{job_candidate_id_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ search resource bookings with member filtering by \"projectId\"", + "name": "✔ search job candidates with connect manager", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "url": { - "raw": "{{URL}}/resourceBookings?projectId={{project_id_16718}}", + "raw": "{{URL}}/jobCandidates", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "jobCandidates" ], "query": [ { @@ -8797,7 +18198,7 @@ }, { "key": "perPage", - "value": "5", + "value": "1", "disabled": true }, { @@ -8807,37 +18208,23 @@ }, { "key": "sortOrder", - "value": "desc", - "disabled": true - }, - { - "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", + "value": "asc", "disabled": true }, { - "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "key": "jobId", + "value": "46225f4c-c2a3-4603-a141-0277e96fabfa", "disabled": true }, { - "key": "rateType", - "value": "hourly", + "key": "userId", + "value": "fe38eed1-af73-41fd-85a2-ac4da1ff09a3", "disabled": true }, { "key": "status", - "value": "sourcing", - "disabled": true - }, - { - "key": "projectIds", - "value": "111, 16705", + "value": "shortlist", "disabled": true - }, - { - "key": "projectId", - "value": "{{project_id_16718}}" } ] } @@ -8845,19 +18232,19 @@ "response": [] }, { - "name": "✘ put resource booking with member", + "name": "✔ put job candidate with connect manager", "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "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-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 \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\",\r\n \"status\": \"selected\"\r\n}", "options": { "raw": { "language": "json" @@ -8865,32 +18252,32 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_member}}" + "jobCandidates", + "{{job_candidate_id_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✘ patch resource booking with member", + "name": "✔ patch job candidate with connect manager", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "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\": \"shortlist\"\r\n}", "options": { "raw": { "language": "json" @@ -8898,27 +18285,27 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_member}}" + "jobCandidates", + "{{job_candidate_id_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✘ delete resource booking with member", + "name": "✘ delete job candidate with connect manager", "request": { "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member_tester1234}}" + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "body": { @@ -8931,53 +18318,125 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_member}}", + "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_member}}" + "jobCandidates", + "{{job_candidate_id_created_for_connect_manager}}" ] } }, "response": [] } ] - } - ] - }, - { - "name": "Request with Connect Manager Role", - "item": [ + }, { - "name": "README", + "name": "Resource Bookings", "item": [ { - "name": "[STUB] all operations except get/search cause 403 error if manager is not member of project", - "request": { - "method": "LOCK", - "header": [], - "url": { - "raw": "" + "name": "Before Test", + "item": [ + { + "name": "create job", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"job_id_created_by_connect_manager\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_16843}},\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", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"resource_booking_id_created_for_connect_manager\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "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 \"billingAccountId\": 80000071\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] } - }, - "response": [] - } - ] - }, - { - "name": "Jobs", - "item": [ + ] + }, { - "name": "✔ create job with connect manager", + "name": "✘ create resource booking with connect manager", "event": [ { "listen": "test", "script": { "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_id_created_by_connect_manager\",data.id);" + "postman.setEnvironmentVariable(\"resource_booking_id_created_by_connect_manager\",data.id);" ], "type": "text/javascript" } @@ -8988,13 +18447,13 @@ "header": [ { "key": "Authorization", - "value": "Bearer {{token_connect_manager_pshahcopmanag2}}", - "type": "text" + "type": "text", + "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" } ], "body": { "mode": "raw", - "raw": "{\n \"projectId\": {{project_id_16843}},\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}", + "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 \"billingAccountId\": 80000071\r\n}", "options": { "raw": { "language": "json" @@ -9002,19 +18461,19 @@ } }, "url": { - "raw": "{{URL}}/jobs", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobs" + "resourceBookings" ] } }, "response": [] }, { - "name": "✔ get job with connect manager", + "name": "✔ get resource booking with connect manager", "request": { "method": "GET", "header": [ @@ -9025,20 +18484,20 @@ } ], "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_connect_manager}}" + "resourceBookings", + "{{resource_booking_id_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ search jobs with connect manager", + "name": "✔ search resource bookings with connect manager", "request": { "method": "GET", "header": [ @@ -9049,22 +18508,22 @@ } ], "url": { - "raw": "{{URL}}/jobs", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobs" + "resourceBookings" ], "query": [ { "key": "page", - "value": "0", + "value": "1", "disabled": true }, { "key": "perPage", - "value": "3", + "value": "5", "disabled": true }, { @@ -9074,37 +18533,17 @@ }, { "key": "sortOrder", - "value": "asc", - "disabled": true - }, - { - "key": "projectId", - "value": "21", - "disabled": true - }, - { - "key": "externalId", - "value": "1212", - "disabled": true - }, - { - "key": "description", - "value": "Dummy", + "value": "desc", "disabled": true }, { "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", - "disabled": true - }, - { - "key": "resourceType", - "value": "Dummy Resource Type", + "value": "2020-09-27", "disabled": true }, { - "key": "skill", - "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "key": "endDate", + "value": "2020-09-27", "disabled": true }, { @@ -9118,13 +18557,8 @@ "disabled": true }, { - "key": "workload", - "value": "full-time", - "disabled": true - }, - { - "key": "title", - "value": "dummy", + "key": "projectIds", + "value": "111, 16705", "disabled": true } ] @@ -9133,7 +18567,7 @@ "response": [] }, { - "name": "✔ put job with connect manager", + "name": "✘ put resource booking with connect manager", "request": { "method": "PUT", "header": [ @@ -9145,7 +18579,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"projectId\": {{project_id_16843}},\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\",\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\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\": \"assigned\",\r\n \"billingAccountId\": 80000071\r\n}", "options": { "raw": { "language": "json" @@ -9153,20 +18587,20 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_connect_manager}}" + "resourceBookings", + "{{resource_booking_id_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ patch job with connect manager", + "name": "✘ patch resource booking with connect manager", "request": { "method": "PATCH", "header": [ @@ -9178,7 +18612,7 @@ ], "body": { "mode": "raw", - "raw": "{\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\": \"fractional\",\n \"skills\": [\n \"cbac57a3-7180-4316-8769-73af64893158\"\n ],\n \"status\": \"sourcing\",\n \"title\": \"Dummy title - at most 64 characters\"\n}", + "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}", "options": { "raw": { "language": "json" @@ -9186,20 +18620,20 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_connect_manager}}" + "resourceBookings", + "{{resource_booking_id_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✘ delete job with connect manager", + "name": "✘ delete resource booking with connect manager", "request": { "method": "DELETE", "header": [ @@ -9219,13 +18653,13 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{job_id_created_by_connect_manager}}", + "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobs", - "{{job_id_created_by_connect_manager}}" + "resourceBookings", + "{{resource_booking_id_created_for_connect_manager}}" ] } }, @@ -9234,20 +18668,74 @@ ] }, { - "name": "Job Candidates", + "name": "Work Periods", "item": [ { "name": "Before Test", "item": [ { - "name": "create job candidate", + "name": "create job", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_candidate_id_created_for_connect_manager\",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(\"job_id_created_by_connect_manager\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_16843}},\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", + "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(\"resource_booking_id_created_for_connect_manager\", response.id);\r", + " }\r", + "});" ], "type": "text/javascript" } @@ -9264,7 +18752,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\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 \"billingAccountId\": 80000071\r\n}", "options": { "raw": { "language": "json" @@ -9272,12 +18760,61 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create work period", + "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(\"workPeriodId_created_for_connect_manager\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_booking_id_created_for_connect_manager}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" ] } }, @@ -9286,14 +18823,17 @@ ] }, { - "name": "✘ create job candidate with connect manager", + "name": "✘ create work period with connect manager", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"job_candidate_id_created_by_connect_manager\",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" } @@ -9310,7 +18850,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{job_id_created_by_connect_manager}}\",\r\n \"userId\": \"fe38eed1-af73-41fd-85a2-ac4da1ff09a3\"\r\n}", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_booking_id_created_for_connect_manager}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -9318,19 +18858,19 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/work-periods", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "work-periods" ] } }, "response": [] }, { - "name": "✔ get job candidate with connect manager", + "name": "✔ get work period with connect manager", "request": { "method": "GET", "header": [ @@ -9341,20 +18881,20 @@ } ], "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_connect_manager}}" + "work-periods", + "{{workPeriodId_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ search job candidates with connect manager", + "name": "✔ search work periods with connect manager", "request": { "method": "GET", "header": [ @@ -9365,12 +18905,12 @@ } ], "url": { - "raw": "{{URL}}/jobCandidates", + "raw": "{{URL}}/work-periods?projectId=16843", "host": [ "{{URL}}" ], "path": [ - "jobCandidates" + "work-periods" ], "query": [ { @@ -9380,7 +18920,7 @@ }, { "key": "perPage", - "value": "1", + "value": "5", "disabled": true }, { @@ -9390,23 +18930,42 @@ }, { "key": "sortOrder", - "value": "asc", + "value": "desc", "disabled": true }, { - "key": "jobId", - "value": "46225f4c-c2a3-4603-a141-0277e96fabfa", + "key": "resourceBookingId", + "value": "{{resource_booking_id_created_for_connect_manager}}", "disabled": true }, { - "key": "userId", - "value": "fe38eed1-af73-41fd-85a2-ac4da1ff09a3", + "key": "resourceBookingIds", + "value": "{{resource_booking_id_created_for_connect_manager}},{{resource_booking_id_created_for_connect_manager}}", "disabled": true }, { - "key": "status", - "value": "shortlist", + "key": "paymentStatus", + "value": "pending", + "disabled": true + }, + { + "key": "startDate", + "value": "2021-03-07", + "disabled": true + }, + { + "key": "endDate", + "value": "2021-03-13", + "disabled": true + }, + { + "key": "userHandle", + "value": "pshah_manager", "disabled": true + }, + { + "key": "projectId", + "value": "16843" } ] } @@ -9414,7 +18973,22 @@ "response": [] }, { - "name": "✔ put job candidate with connect manager", + "name": "✘ put work period with connect manager", + "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": [ @@ -9426,7 +19000,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 \"resourceBookingId\": \"{{resource_booking_id_created_for_connect_manager}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -9434,20 +19008,35 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_connect_manager}}" + "work-periods", + "{{workPeriodId_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ patch job candidate with connect manager", + "name": "✘ patch work period with connect manager", + "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": [ @@ -9459,7 +19048,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_booking_id_created_for_connect_manager}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", "options": { "raw": { "language": "json" @@ -9467,20 +19056,35 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_connect_manager}}" + "work-periods", + "{{workPeriodId_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✘ delete job candidate with connect manager", + "name": "✘ delete work period with connect manager", + "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": [ @@ -9500,13 +19104,13 @@ } }, "url": { - "raw": "{{URL}}/jobCandidates/{{job_candidate_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-periods/{{workPeriodId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "jobCandidates", - "{{job_candidate_id_created_for_connect_manager}}" + "work-periods", + "{{workPeriodId_created_for_connect_manager}}" ] } }, @@ -9515,20 +19119,74 @@ ] }, { - "name": "Resource Bookings", + "name": "Work Period Payments", "item": [ { "name": "Before Test", "item": [ { - "name": "create resource booking", + "name": "✔ create job", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resource_booking_id_created_for_connect_manager\",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(\"job_id_created_for_connect_manager\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_administrator}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"projectId\": {{project_id_17234}},\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", + "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(\"resource_bookings_id_created_for_connect_manager\", response.id);\r", + " }\r", + "});" ], "type": "text/javascript" } @@ -9545,7 +19203,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-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\": {{project_id_17234}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{job_id_created_for_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 \"billingAccountId\": 80000071\r\n}", "options": { "raw": { "language": "json" @@ -9563,18 +19221,119 @@ } }, "response": [] + }, + { + "name": "✔ create work period", + "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(\"workPeriodId_created_for_connect_manager\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"resourceBookingId\": \"{{resource_bookings_id_created_for_connect_manager}}\",\r\n \"startDate\": \"2021-03-07\",\r\n \"endDate\": \"2021-03-13\",\r\n \"daysWorked\": 2,\r\n \"memberRate\": 13.13,\r\n \"customerRate\": 13.13,\r\n \"paymentStatus\": \"pending\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-periods", + "host": [ + "{{URL}}" + ], + "path": [ + "work-periods" + ] + } + }, + "response": [] + }, + { + "name": "✔ create work period payment", + "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(\"workPeriodPaymentId_created_for_connect_manager\", response.id);\r", + " }\r", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_administrator}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_for_connect_manager}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/work-period-payments", + "host": [ + "{{URL}}" + ], + "path": [ + "work-period-payments" + ] + } + }, + "response": [] } ] }, { - "name": "✘ create resource booking with connect manager", + "name": "✘ create work period payment with connect manager", "event": [ { "listen": "test", "script": { "exec": [ - "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"resource_booking_id_created_by_connect_manager\",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" } @@ -9591,7 +19350,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-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 \"workPeriodId\": \"{{workPeriodId_created_for_connect_manager}}\",\r\n \"amount\": 600,\r\n \"status\": \"completed\"\r\n}", "options": { "raw": { "language": "json" @@ -9599,19 +19358,34 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/work-period-payments", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "work-period-payments" ] } }, "response": [] }, { - "name": "✔ get resource booking with connect manager", + "name": "✘ get work period payment with connect manager", + "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": "GET", "header": [ @@ -9622,20 +19396,35 @@ } ], "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_connect_manager}}" + "work-period-payments", + "{{workPeriodPaymentId_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✔ search resource bookings with connect manager", + "name": "✘ search work period payments with connect manager", + "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": "GET", "header": [ @@ -9646,12 +19435,12 @@ } ], "url": { - "raw": "{{URL}}/resourceBookings", + "raw": "{{URL}}/work-period-payments", "host": [ "{{URL}}" ], "path": [ - "resourceBookings" + "work-period-payments" ], "query": [ { @@ -9666,7 +19455,7 @@ }, { "key": "sortBy", - "value": "id", + "value": "status", "disabled": true }, { @@ -9675,28 +19464,18 @@ "disabled": true }, { - "key": "startDate", - "value": "2020-09-27T04:17:23.131Z", - "disabled": true - }, - { - "key": "endDate", - "value": "2020-09-27T04:17:23.131Z", + "key": "workPeriodId", + "value": "{{workPeriodPaymentId_created_for_connect_manager}}", "disabled": true }, { - "key": "rateType", - "value": "hourly", + "key": "workPeriodIds", + "value": "{{workPeriodPaymentId_created_for_connect_manager}},{{workPeriodPaymentId_created_for_connect_manager}}", "disabled": true }, { "key": "status", - "value": "sourcing", - "disabled": true - }, - { - "key": "projectIds", - "value": "111, 16705", + "value": "completed", "disabled": true } ] @@ -9705,7 +19484,22 @@ "response": [] }, { - "name": "✘ put resource booking with connect manager", + "name": "✘ put work period payment with connect manager", + "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": [ @@ -9717,7 +19511,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-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 \"workPeriodId\": \"{{workPeriodId_created_for_connect_manager}}\",\r\n \"amount\": 1600,\r\n \"status\": \"completed\"\r\n}", "options": { "raw": { "language": "json" @@ -9725,55 +19519,37 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_connect_manager}}" + "work-period-payments", + "{{workPeriodPaymentId_created_for_connect_manager}}" ] } }, "response": [] }, { - "name": "✘ patch resource booking with connect manager", - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token_connect_manager_pshahcopmanag2}}" - } - ], - "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" - } + "name": "✘ patch work period payment with connect manager", + "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" } - }, - "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", - "host": [ - "{{URL}}" - ], - "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_connect_manager}}" - ] } - }, - "response": [] - }, - { - "name": "✘ delete resource booking with connect manager", + ], "request": { - "method": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -9783,7 +19559,7 @@ ], "body": { "mode": "raw", - "raw": "", + "raw": "{\r\n \"workPeriodId\": \"{{workPeriodId_created_for_connect_manager}}\",\r\n \"amount\": 450,\r\n \"status\": \"cancelled\"\r\n}", "options": { "raw": { "language": "json" @@ -9791,13 +19567,13 @@ } }, "url": { - "raw": "{{URL}}/resourceBookings/{{resource_booking_id_created_for_connect_manager}}", + "raw": "{{URL}}/work-period-payments/{{workPeriodPaymentId_created_for_connect_manager}}", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resource_booking_id_created_for_connect_manager}}" + "work-period-payments", + "{{workPeriodPaymentId_created_for_connect_manager}}" ] } }, @@ -9810,4 +19586,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 981e5b91..940be373 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -4,16 +4,17 @@ info: description: Bookings microservice version: 1.0.0 servers: -- url: /api/{apiVersion}/ - variables: - apiVersion: - default: 'v5' - description: The REST API version + - url: /api/{apiVersion}/ + variables: + apiVersion: + default: "v5" + description: The REST API version tags: - name: Jobs - name: JobCandidates - name: ResourceBookings - name: Teams + - name: WorkPeriods paths: /jobs: post: @@ -34,38 +35,38 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/JobRequestBody' + $ref: "#/components/schemas/JobRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/Job' - '400': + $ref: "#/components/schemas/Job" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" get: tags: - Jobs @@ -96,7 +97,7 @@ paths: schema: type: string default: id - enum: ['id','createdAt','startDate','rateType','status'] + enum: ["id", "createdAt", "startDate", "rateType", "status"] description: The sort by column. - in: query name: sortOrder @@ -104,7 +105,7 @@ paths: schema: type: string default: desc - enum: ['desc','asc'] + enum: ["desc", "asc"] description: The sort order. - in: query name: projectId @@ -161,32 +162,32 @@ paths: required: false schema: type: string - enum: ['full-time', 'fractional'] + enum: ["full-time", "fractional"] description: The rate type. - in: query name: rateType required: false schema: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: The rate type. - in: query name: status required: false schema: type: string - enum: ['sourcing', 'in-review', 'assigned', 'closed', 'cancelled'] + enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] description: The rate type. responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/Job' - + $ref: "#/components/schemas/Job" + headers: X-Next-Page: schema: @@ -216,41 +217,41 @@ paths: schema: type: string description: Pagination link header. - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /jobs/{id}: get: - tags: + tags: - Jobs description: | Get job information by id. - + **Authorization** All topcoder members are allowed security: - bearerAuth: [] - parameters: + parameters: - in: path name: id description: The job id. @@ -264,50 +265,50 @@ paths: schema: type: boolean responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/Job' - '400': + $ref: "#/components/schemas/Job" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" delete: - tags: + tags: - Jobs - description: | + description: | Delete the job. **Authorization** Every topcoder member can delete the job he/she created. bookingmanager can delete all jobs. - security: + security: - bearerAuth: [] parameters: - in: path @@ -318,40 +319,40 @@ paths: type: string format: uuid responses: - '204': + "204": description: OK - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" put: - tags: + tags: - Jobs description: | Update the job. @@ -376,47 +377,47 @@ paths: application/json: schema: allOf: - - $ref: '#/components/schemas/JobRequestBody' - - $ref: '#/components/schemas/JobPatchRequestBody' + - $ref: "#/components/schemas/JobRequestBody" + - $ref: "#/components/schemas/JobPatchRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/Job' - '400': + $ref: "#/components/schemas/Job" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" patch: - tags: + tags: - Jobs description: | Update job. @@ -440,44 +441,44 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/JobPatchRequestBody' + $ref: "#/components/schemas/JobPatchRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/Job' - '400': + $ref: "#/components/schemas/Job" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /jobCandidates: post: tags: @@ -492,44 +493,44 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/JobCandidateRequestBody' + $ref: "#/components/schemas/JobCandidateRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/JobCandidate' - '400': + $ref: "#/components/schemas/JobCandidate" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" get: tags: - JobCandidates @@ -560,7 +561,7 @@ paths: schema: type: string default: id - enum: ['id','status'] + enum: ["id", "status"] description: The sort by column. - in: query name: sortOrder @@ -568,7 +569,7 @@ paths: schema: type: string default: desc - enum: ['desc','asc'] + enum: ["desc", "asc"] - in: query name: jobId required: false @@ -588,7 +589,16 @@ paths: required: false schema: type: string - enum: ['open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview', 'topcoder-rejected'] + enum: + [ + "open", + "selected", + "shortlist", + "rejected", + "cancelled", + "interview", + "topcoder-rejected", + ] description: The job candidate status. - in: query name: externalId @@ -597,15 +607,15 @@ paths: type: string description: The external id. responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/JobCandidate' - + $ref: "#/components/schemas/JobCandidate" + headers: X-Next-Page: schema: @@ -635,41 +645,41 @@ paths: schema: type: string description: Pagination link header. - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /jobCandidates/{id}: get: - tags: + tags: - JobCandidates description: | Get job candidate information by id. - + **Authorization** Topcoder token with read job candidate scope is allowed security: - bearerAuth: [] - parameters: + parameters: - in: path name: id description: The job candidate id. @@ -684,50 +694,50 @@ paths: schema: type: boolean responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/JobCandidate' - '400': + $ref: "#/components/schemas/JobCandidate" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" delete: - tags: + tags: - JobCandidates - description: | + description: | Delete the job. **Authorization** Topcoder token with delete job candidate scope is allowed - security: + security: - bearerAuth: [] parameters: - in: path @@ -738,40 +748,40 @@ paths: type: string format: uuid responses: - '204': + "204": description: OK - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" put: - tags: + tags: - JobCandidates description: | Update the job candidate. @@ -791,47 +801,47 @@ paths: application/json: schema: allOf: - - $ref: '#/components/schemas/JobCandidateRequestBody' - - $ref: '#/components/schemas/JobCandidatePatchRequestBody' + - $ref: "#/components/schemas/JobCandidateRequestBody" + - $ref: "#/components/schemas/JobCandidatePatchRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/JobCandidate' - '400': + $ref: "#/components/schemas/JobCandidate" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" patch: - tags: + tags: - JobCandidates description: | Partail update job candidate. @@ -851,44 +861,44 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/JobCandidatePatchRequestBody' + $ref: "#/components/schemas/JobCandidatePatchRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/JobCandidate' - '400': + $ref: "#/components/schemas/JobCandidate" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /resourceBookings: post: tags: @@ -903,44 +913,44 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ResourceBookingRequestBody' + $ref: "#/components/schemas/ResourceBookingRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/ResourceBooking' - '400': + $ref: "#/components/schemas/ResourceBooking" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" get: tags: - ResourceBookings @@ -971,7 +981,16 @@ paths: schema: type: string default: id - enum: ['id','status','startDate','endDate','rateType','customerRate','memberRate'] + enum: + [ + "id", + "status", + "startDate", + "endDate", + "rateType", + "customerRate", + "memberRate", + ] description: The sort by column. - in: query name: sortOrder @@ -979,72 +998,929 @@ paths: schema: type: string default: desc - enum: ['desc','asc'] + enum: ["desc", "asc"] - in: query name: status required: false schema: type: string - enum: ['assigned', 'in-progress', 'completed'] + enum: ["assigned", "in-progress", "completed"] description: The status. - in: query name: startDate required: false schema: type: string - format: date-time + format: date description: The resource booking start date. - in: query name: endDate required: false schema: type: string - format: date-time + format: date description: The resource booking end date. - in: query name: rateType required: false schema: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: The rate type. - in: query - name: jobId + name: jobId + required: false + schema: + type: string + format: uuid + description: The job id. + - in: query + name: userId + required: false + schema: + type: string + format: uuid + description: The job id. + - in: query + name: projectId + required: false + schema: + type: integer + description: The project id. + - in: query + name: projectIds + required: false + schema: + type: string + description: comma separated project ids. + + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ResourceBooking" + + headers: + X-Next-Page: + schema: + type: integer + description: The index of the next page + X-Page: + schema: + type: integer + description: The index of the current page (starting at 1) + X-Per-Page: + schema: + type: integer + description: The number of items to list per page + X-Prev-Page: + schema: + type: integer + description: The index of the previous page + X-Total: + schema: + type: integer + description: The total number of items + X-Total-Pages: + schema: + type: integer + description: The total number of pages + Link: + schema: + type: string + description: Pagination link header. + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /resourceBookings/{id}: + get: + tags: + - ResourceBookings + description: | + Get resource booking by id. + + **Authorization** Topcoder token with read resource booking scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The resource booking id. + required: true + schema: + type: string + format: uuid + - in: query + name: fromDb + description: get data from db or not. + required: false + schema: + type: boolean + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/ResourceBooking" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + delete: + tags: + - ResourceBookings + description: | + Delete the resource booking. + + **Authorization** Topcoder token with delete resource booking scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The id of resource booking. + required: true + schema: + type: string + format: uuid + responses: + "204": + description: OK + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + put: + tags: + - ResourceBookings + description: | + Update the resource booking. + + **Authorization** Topcoder token with update resource booking scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The id of resource booking. + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ResourceBookingRequestBody" + - $ref: "#/components/schemas/ResourceBookingPatchRequestBody" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/ResourceBooking" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + patch: + tags: + - ResourceBookings + description: | + Partial Update resource booking. + + **Authorization** Topcoder token with update job candidate scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The id of resource booking. + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ResourceBookingPatchRequestBody" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/ResourceBooking" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /work-periods: + post: + tags: + - WorkPeriods + description: | + Create Work Period. + + **Authorization** Topcoder token with write Work period scope is allowed + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriodRequestBody" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriod" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + get: + tags: + - WorkPeriods + description: | + Search work period. + + **Authorization** Topcoder token with read work period scope is allowed + security: + - bearerAuth: [] + parameters: + - in: query + name: page + required: false + schema: + type: integer + default: 1 + description: The page number. + - in: query + name: perPage + required: false + schema: + type: integer + default: 20 + description: The number of items to list per page. + - in: query + name: sortBy + required: false + schema: + type: string + default: id + enum: + [ + "id", + "resourceBookingId", + "userHandle", + "projectId", + "paymentStatus", + "startDate", + "endDate", + "daysWorked", + "customerRate", + "memberRate", + ] + description: The sort by column. + - in: query + name: sortOrder + required: false + schema: + type: string + default: desc + enum: ["desc", "asc"] + - in: query + name: resourceBookingId + required: false + schema: + type: string + format: uuid + description: The resource booking id. + - in: query + name: resourceBookingIds + required: false + schema: + oneOf: + - type: array + items: + type: string + format: uuid + - type: string + description: comma separated resource booking ids. + - in: query + name: paymentStatus + required: false + schema: + type: string + enum: ["pending", "partially-completed", "completed", "cancelled"] + description: The payment status. + - in: query + name: startDate + required: false + schema: + type: string + format: date + pattern: '^\d{4}-\d{2}-\d{2}$' + description: The work period start date. + - in: query + name: endDate + required: false + schema: + type: string + format: date + pattern: '^\d{4}-\d{2}-\d{2}$' + description: The work period end date. + - in: query + name: userHandle + required: false + schema: + type: string + description: The user handle. + - in: query + name: projectId + required: false + schema: + type: integer + description: The project id. + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/WorkPeriod" + headers: + X-Next-Page: + schema: + type: integer + description: The index of the next page + X-Page: + schema: + type: integer + description: The index of the current page (starting at 1) + X-Per-Page: + schema: + type: integer + description: The number of items to list per page + X-Prev-Page: + schema: + type: integer + description: The index of the previous page + X-Total: + schema: + type: integer + description: The total number of items + X-Total-Pages: + schema: + type: integer + description: The total number of pages + Link: + schema: + type: string + description: Pagination link header. + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /work-periods/{id}: + get: + tags: + - WorkPeriods + description: | + Get work period by id. + + **Authorization** Topcoder token with read work period scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The work period id. + required: true + schema: + type: string + format: uuid + - in: query + name: fromDb + description: get data from db or not. + required: false + schema: + type: boolean + default: false + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriod" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + delete: + tags: + - WorkPeriods + description: | + Delete the work period. + + **Authorization** Topcoder token with delete work period scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The id of work period. + required: true + schema: + type: string + format: uuid + responses: + "204": + description: OK + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + put: + tags: + - WorkPeriods + description: | + Update the work period. + + **Authorization** Topcoder token with update work period scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The id of work period. + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriodRequestBody" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriod" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + patch: + tags: + - WorkPeriods + description: | + Partial Update work period. + + **Authorization** Topcoder token with update work period scope is allowed + security: + - bearerAuth: [] + parameters: + - in: path + name: id + description: The id of work period. + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriodPatchRequestBody" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriod" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /work-period-payments: + post: + tags: + - WorkPeriodPayments + description: | + Create Work Period Payment. + + **Authorization** Topcoder token with write Work period payment scope is allowed + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriodPaymentRequestBody" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/WorkPeriodPayment" + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + get: + tags: + - WorkPeriodPayments + description: | + Search work period payment. + + **Authorization** Topcoder token with read work period payment scope is allowed + security: + - bearerAuth: [] + parameters: + - in: query + name: page + required: false + schema: + type: integer + default: 1 + description: The page number. + - in: query + name: perPage + required: false + schema: + type: integer + default: 20 + description: The number of items to list per page. + - in: query + name: sortBy + required: false + schema: + type: string + default: createdAt + enum: ["status", "amount", "createdAt", "updatedAt"] + description: The sort by column. + - in: query + name: sortOrder required: false schema: type: string - format: uuid - description: The job id. + default: desc + enum: ["desc", "asc"] - in: query - name: userId + name: workPeriodId required: false schema: type: string format: uuid - description: The job id. + description: The work period id. - in: query - name: projectId + name: workPeriodIds required: false schema: - type: integer - description: The project id. + oneOf: + - type: array + items: + type: string + format: uuid + - type: string + description: comma separated work period ids. - in: query - name: projectIds + name: status required: false schema: type: string - description: comma separated project ids. - + enum: ["completed", "cancelled"] + description: The payment status. responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/ResourceBooking' - + $ref: "#/components/schemas/WorkPeriodPayment" headers: X-Next-Page: schema: @@ -1074,44 +1950,44 @@ paths: schema: type: string description: Pagination link header. - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' - /resourceBookings/{id}: + $ref: "#/components/schemas/Error" + /work-period-payments/{id}: get: - tags: - - ResourceBookings + tags: + - WorkPeriodPayments description: | - Get resource booking by id. - - **Authorization** Topcoder token with read resource booking scope is allowed + Get work period payment by id. + + **Authorization** Topcoder token with read work period payment scope is allowed security: - bearerAuth: [] - parameters: + parameters: - in: path name: id - description: The resource booking id. + description: The work period payment id. required: true schema: type: string @@ -1122,106 +1998,57 @@ paths: required: false schema: type: boolean + default: false responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/ResourceBooking' - '400': - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: Not authenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - tags: - - ResourceBookings - description: | - Delete the resource booking. - - **Authorization** Topcoder token with delete resource booking scope is allowed - security: - - bearerAuth: [] - parameters: - - in: path - name: id - description: The id of resource booking. - required: true - schema: - type: string - format: uuid - responses: - '204': - description: OK - '400': + $ref: "#/components/schemas/WorkPeriodPayment" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" put: - tags: - - ResourceBookings + tags: + - WorkPeriodPayments description: | - Update the resource booking. + Update the work period payment. - **Authorization** Topcoder token with update resource booking scope is allowed + **Authorization** Topcoder token with update work period payment scope is allowed security: - bearerAuth: [] parameters: - in: path name: id - description: The id of resource booking. + description: The id of work period payment. required: true schema: type: string @@ -1230,59 +2057,57 @@ paths: content: application/json: schema: - allOf: - - $ref: '#/components/schemas/ResourceBookingRequestBody' - - $ref: '#/components/schemas/ResourceBookingPatchRequestBody' + $ref: "#/components/schemas/WorkPeriodPaymentRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/ResourceBooking' - '400': + $ref: "#/components/schemas/WorkPeriodPayment" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" patch: - tags: - - ResourceBookings + tags: + - WorkPeriodPayments description: | - Partial Update resource booking. + Partial Update work period payment. - **Authorization** Topcoder token with update job candidate scope is allowed + **Authorization** Topcoder token with update work period payment scope is allowed security: - bearerAuth: [] parameters: - in: path name: id - description: The id of resource booking. + description: The id of work period payment. required: true schema: type: string @@ -1291,44 +2116,44 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ResourceBookingPatchRequestBody' + $ref: "#/components/schemas/WorkPeriodPaymentPatchRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/ResourceBooking' - '400': + $ref: "#/components/schemas/WorkPeriodPayment" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams: get: tags: @@ -1356,7 +2181,17 @@ paths: schema: type: string default: createdAt - enum: ['createdAt', 'updatedAt', 'lastActivityAt', 'id', 'status', 'name', 'type', 'best match'] + enum: + [ + "createdAt", + "updatedAt", + "lastActivityAt", + "id", + "status", + "name", + "type", + "best match", + ] description: The sort by column. - in: query name: sortOrder @@ -1364,7 +2199,7 @@ paths: schema: type: string default: desc - enum: ['desc','asc'] + enum: ["desc", "asc"] description: The sort order. Not allowed when sortBy is `best match`. - in: query name: name @@ -1372,18 +2207,18 @@ paths: schema: type: string description: filter by name, case-insensitive; support wildcard match. - example: '*taas*' + example: "*taas*" security: - bearerAuth: [] responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/Team' + $ref: "#/components/schemas/Team" headers: X-Next-Page: schema: @@ -1413,24 +2248,24 @@ paths: schema: type: string description: Pagination link header. - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/{id}: get: tags: @@ -1447,36 +2282,36 @@ paths: type: integer description: The team/project id. responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/TeamDetail' - '400': + $ref: "#/components/schemas/TeamDetail" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Not authorized content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/{id}/jobs/{jobId}: get: tags: @@ -1500,42 +2335,42 @@ paths: format: uuid description: The job id. responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/JobDetail' - '400': + $ref: "#/components/schemas/JobDetail" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Not authorized content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/{id}/members: post: tags: @@ -1555,44 +2390,44 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/AddMembersRequestBody' + $ref: "#/components/schemas/AddMembersRequestBody" responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/AddMembersResponseBody' - '400': + $ref: "#/components/schemas/AddMembersResponseBody" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Not authorized content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" get: tags: - Teams @@ -1621,38 +2456,38 @@ paths: type: string description: Filtered by a specific role. responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/ProjectMember' - '400': + $ref: "#/components/schemas/ProjectMember" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Not authorized content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/{id}/invites: get: @@ -1677,38 +2512,38 @@ paths: type: string description: Fields to be returned. responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/ProjectMemberInvite' - '400': + $ref: "#/components/schemas/ProjectMemberInvite" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Not authorized content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/{id}/members/{projectMemberId}: delete: tags: @@ -1732,38 +2567,38 @@ paths: type: integer description: The id of the project member. responses: - '204': + "204": description: OK - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '404': + $ref: "#/components/schemas/Error" + "404": description: Not Found content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/skills: get: tags: @@ -1793,14 +2628,14 @@ paths: security: - bearerAuth: [] responses: - '200': + "200": description: OK content: application/json: schema: type: array items: - $ref: '#/components/schemas/UbahnSkill' + $ref: "#/components/schemas/UbahnSkill" headers: X-Next-Page: schema: @@ -1830,70 +2665,116 @@ paths: schema: type: string description: Pagination link header. - '400': + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /taas-teams/email: post: - tags: + tags: - Teams - description: | + description: | Send emails through one of predefined templates. - security: + security: - bearerAuth: [] requestBody: content: application/json: schema: - $ref: '#/components/schemas/TeamEmailRequestBody' + $ref: "#/components/schemas/TeamEmailRequestBody" + responses: + "204": + description: OK + "400": + description: Bad request + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "401": + description: Not authenticated + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "403": + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + + /taas-teams/me: + get: + tags: + - Teams + description: | + Return details about the current user. + security: + - bearerAuth: [] responses: - '204': + "200": description: OK - '400': + content: + application/json: + schema: + $ref: "#/components/schemas/UbahnUser" + "400": description: Bad request content: application/json: schema: - $ref: '#/components/schemas/Error' - '401': + $ref: "#/components/schemas/Error" + "401": description: Not authenticated content: application/json: schema: - $ref: '#/components/schemas/Error' - '403': + $ref: "#/components/schemas/Error" + "403": description: Forbidden content: application/json: schema: - $ref: '#/components/schemas/Error' - '500': + $ref: "#/components/schemas/Error" + "404": + description: Not Found + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + "500": description: Internal Server Error content: application/json: schema: - $ref: '#/components/schemas/Error' + $ref: "#/components/schemas/Error" /health: get: tags: @@ -1901,18 +2782,18 @@ paths: description: | Get health status of the app. responses: - '200': + "200": description: OK content: application/json: schema: - $ref: '#/components/schemas/CheckRun' - '503': + $ref: "#/components/schemas/CheckRun" + "503": description: Service unavailable content: application/json: schema: - $ref: '#/components/schemas/CheckRun' + $ref: "#/components/schemas/CheckRun" components: securitySchemes: bearerAuth: @@ -1971,11 +2852,11 @@ components: description: "The resource type of job." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." workload: type: string - enum: ['full-time', 'fractional'] + enum: ["full-time", "fractional"] description: "The workload of the job." skills: type: array @@ -1986,13 +2867,13 @@ components: description: "The skill id." status: type: string - enum: ['sourcing', 'in-review', 'assigned', 'closed', 'cancelled'] + enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] description: "The job status." candidates: type: array description: "The job candidates." items: - $ref: '#/components/schemas/JobCandidate' + $ref: "#/components/schemas/JobCandidate" isApplicationPageActive: type: boolean default: false @@ -2002,7 +2883,7 @@ components: description: "The job created date." createdBy: type: string - example: 'topocder user' + example: "topocder user" description: "The user who created the job.(Will get the user info from the token)" updatedAt: type: string @@ -2010,7 +2891,7 @@ components: description: "The job last updated at." updatedBy: type: string - example: 'topcoder user' + example: "topcoder user" description: "The user who updated the job last time.(Will get the user info from the token)" JobRequestBody: required: @@ -2038,7 +2919,7 @@ components: maxLength: 64 status: type: string - enum: ['sourcing', 'in-review', 'assigned', 'closed', 'cancelled'] + enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] description: "The job status." default: sourcing startDate: @@ -2060,11 +2941,11 @@ components: description: "The resource type of job." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." workload: type: string - enum: ['full-time', 'fractional'] + enum: ["full-time", "fractional"] description: "The workload of the job." skills: type: array @@ -2077,7 +2958,7 @@ components: type: boolean default: false JobCandidate: - required: + required: - id - jobId - userId @@ -2098,7 +2979,16 @@ components: description: "The user id." status: type: string - enum: ['open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview', 'topcoder-rejected'] + enum: + [ + "open", + "selected", + "shortlist", + "rejected", + "cancelled", + "interview", + "topcoder-rejected", + ] description: "The job candidate status." externalId: type: string @@ -2114,7 +3004,7 @@ components: description: "The job created date." createdBy: type: string - example: 'topocder user' + example: "topocder user" description: "The user who created the job.(Will get the user info from the token)" updatedAt: type: string @@ -2122,10 +3012,10 @@ components: description: "The job last updated at." updatedBy: type: string - example: 'topcoder user' + example: "topcoder user" description: "The user who updated the job last time.(Will get the user info from the token)" JobCandidateRequestBody: - required: + required: - jobId - userId properties: @@ -2140,7 +3030,7 @@ components: description: "The user id." status: type: string - enum: ['open', 'selected', 'shortlist', 'rejected', 'cancelled'] + enum: ["open", "selected", "shortlist", "rejected", "cancelled"] description: "The job candidate status." default: open externalId: @@ -2155,7 +3045,16 @@ components: properties: status: type: string - enum: ['open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview', 'topcoder-rejected'] + enum: + [ + "open", + "selected", + "shortlist", + "rejected", + "cancelled", + "interview", + "topcoder-rejected", + ] externalId: type: string example: "1212" @@ -2168,7 +3067,7 @@ components: properties: status: type: string - enum: ['sourcing', 'in-review', 'assigned', 'closed', 'cancelled'] + enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] description: type: string example: "Dummy Description" @@ -2192,11 +3091,11 @@ components: description: "The resource type of job." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." workload: type: string - enum: ['full-time', 'fractional'] + enum: ["full-time", "fractional"] description: "The workload of the job." skills: type: array @@ -2237,17 +3136,17 @@ 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 - format: date-time - example: "2020-09-27T04:17:23.131Z" + format: date + example: "2020-09-27" description: "The job start date." endDate: type: string - format: date-time - example: "2020-09-27T04:17:23.131Z" + format: date + example: "2020-09-28" description: "The job end date." memberRate: type: integer @@ -2261,15 +3160,19 @@ components: description: "The customer rate." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." + billingAccountId: + type: integer + example: 80000071 + description: 'the billing account id for payments' createdAt: type: string format: date-time description: "The job created date." createdBy: type: string - example: 'topocder user' + example: "topocder user" description: "The user who created the job.(Will get the user info from the token)" updatedAt: type: string @@ -2277,7 +3180,7 @@ components: description: "The job last updated at." updatedBy: type: string - example: 'topcoder user' + example: "topcoder user" description: "The user who updated the job last time.(Will get the user info from the token)" ResourceBookingRequestBody: required: @@ -2300,18 +3203,18 @@ 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: type: string - format: date-time - example: "2020-09-27T04:17:23.131Z" + format: date + example: "2020-09-27" description: "The job start date." endDate: type: string - format: date-time - example: "2020-09-27T04:17:23.131Z" + format: date + example: "2020-09-28" description: "The job end date." memberRate: type: number @@ -2325,22 +3228,26 @@ components: description: "The customer rate." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." + billingAccountId: + type: integer + example: 80000071 + description: 'the billing account id for payments' ResourceBookingPatchRequestBody: properties: status: type: string - enum: ['sourcing', 'in-review', 'assigned', 'closed', 'cancelled'] + enum: ["assigned", "closed", "cancelled"] startDate: type: string - format: date-time - example: "2020-09-27T04:17:23.131Z" + format: date + example: "2020-09-27" description: "The job start date." endDate: type: string - format: date-time - example: "2020-09-27T04:17:23.131Z" + format: date + example: "2020-09-28" description: "The job end date." memberRate: type: number @@ -2354,8 +3261,242 @@ components: description: "The customer rate." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." + billingAccountId: + type: integer + example: 80000071 + description: 'the billing account id for payments' + WorkPeriod: + required: + - id + - resourceBookingId + - userHandle + - projectId + - startDate + - endDate + - paymentStatus + - createdAt + - createdBy + properties: + id: + type: string + format: uuid + description: "The work period id." + resourceBookingId: + type: string + format: uuid + description: "The resource booking id." + userHandle: + type: string + example: "eisbilir" + description: "The user handle." + projectId: + type: integer + example: 123 + description: "The project id." + startDate: + type: string + format: date + example: "2021-03-07" + description: "The start date of work period. Should be always Sunday." + endDate: + type: string + format: date + example: "2021-03-13" + description: "The end date of work period. Should be always Saturday." + daysWorked: + type: integer + example: 2 + description: "The count of the days worked for that work period." + memberRate: + type: integer + format: float + example: 13.13 + description: "The member rate." + customerRate: + type: integer + format: float + example: 13.13 + description: "The customer rate." + paymentStatus: + type: string + enum: ["pending", "partially-completed", "completed", "cancelled"] + description: "The payment status." + payments: + type: array + description: "The payments related with work period" + items: + $ref: "#/components/schemas/WorkPeriodPayment" + createdAt: + type: string + format: date-time + description: "The work period created date." + createdBy: + type: string + format: uuid + description: "The user Id who created the work period.(Will get the user info from the token)" + updatedAt: + type: string + format: date-time + description: "The work period last updated at." + updatedBy: + type: string + format: uuid + description: "The user Id who updated the work period last time.(Will get the user info from the token)" + WorkPeriodRequestBody: + required: + - resourceBookingId + - startDate + - endDate + - paymentStatus + properties: + resourceBookingId: + type: string + format: uuid + description: "The resource booking id." + startDate: + type: string + format: date + example: "2021-03-07" + description: "The start date of work period. Should be always Sunday." + endDate: + type: string + format: date + example: "2021-03-13" + description: "The end date of work period. Should be always Saturday." + daysWorked: + type: integer + example: 2 + description: "The count of the days worked for that work period." + memberRate: + type: integer + format: float + example: 13.13 + description: "The member rate." + customerRate: + type: integer + format: float + example: 13.13 + description: "The customer rate." + paymentStatus: + type: string + enum: ["pending", "partially-completed", "completed", "cancelled"] + description: "The payment status." + WorkPeriodPatchRequestBody: + properties: + resourceBookingId: + type: string + format: uuid + description: "The resource booking id." + startDate: + type: string + format: date + example: "2021-03-07" + description: "The start date of work period. Should be always Sunday." + endDate: + type: string + format: date + example: "2021-03-13" + description: "The end date of work period. Should be always Saturday." + daysWorked: + type: integer + example: 2 + description: "The count of the days worked for that work period." + memberRate: + type: integer + format: float + example: 13.13 + description: "The member rate." + customerRate: + type: integer + format: float + example: 13.13 + description: "The customer rate." + paymentStatus: + type: string + enum: ["pending", "partially-completed", "completed", "cancelled"] + description: "The payment status." + WorkPeriodPayment: + required: + - id + - workPeriodId + - challengeId + - amount + - status + - createdAt + - createdBy + properties: + id: + type: string + format: uuid + description: "The work period payment id." + workPeriodId: + type: string + format: uuid + description: "The work period id." + challengeId: + type: string + format: uuid + description: "The challenge id." + amount: + type: integer + example: 2 + description: "The amount to be paid." + status: + type: string + enum: ["completed", "cancelled"] + description: "The payment status." + billingAccountId: + type: integer + example: 80000071 + description: 'the billing account id for payments' + createdAt: + type: string + format: date-time + description: "The work period payment created date." + createdBy: + type: string + format: uuid + description: "The user Id who created the work period payment.(Will get the user info from the token)" + updatedAt: + type: string + format: date-time + description: "The work period payment last updated at." + updatedBy: + type: string + format: uuid + description: "The user Id who updated the work period payment last time.(Will get the user info from the token)" + WorkPeriodPaymentRequestBody: + required: + - workPeriodId + properties: + workPeriodId: + type: string + format: uuid + description: "The work period id." + amount: + type: integer + example: 2 + description: "The amount to be paid." + status: + type: string + enum: ["completed", "cancelled"] + description: "The payment status." + WorkPeriodPaymentPatchRequestBody: + properties: + workPeriodId: + type: string + format: uuid + description: "The work period id." + amount: + type: integer + example: 2 + description: "The amount to be paid." + status: + type: string + enum: ["completed", "cancelled"] + description: "The payment status." CheckRun: type: object properties: @@ -2378,13 +3519,46 @@ components: items: type: object description: "The invites of the project" - example: [{"createdAt": "2021-02-08T09:21:00.885Z", "createdBy": 40159127, "deletedBy": null, "email": null, "id": 3008, "projectId": 16819, "role": "customer", "status": "pending", "updatedAt": "2021-02-08T09:21:00.885Z", "updatedBy": 40159127, "userId": 40153913}] + example: + [ + { + "createdAt": "2021-02-08T09:21:00.885Z", + "createdBy": 40159127, + "deletedBy": null, + "email": null, + "id": 3008, + "projectId": 16819, + "role": "customer", + "status": "pending", + "updatedAt": "2021-02-08T09:21:00.885Z", + "updatedBy": 40159127, + "userId": 40153913, + }, + ] members: type: array items: type: object description: "The members of the project" - example: [{"lastName": "L_NAME", "role": "customer", "updatedBy": 21926562, "handle": "Tester123", "userId": 21926562, "deletedBy": null, "createdAt": "2021-01-12T10:58:26.237Z", "firstName": "F_NAME", "createdBy": 21926562, "isPrimary": false, "id": 13833, "projectId": 16893, "email": "email@domain.com.z", "updatedAt": "2021-01-12T10:58:26.237Z"}] + example: + [ + { + "lastName": "L_NAME", + "role": "customer", + "updatedBy": 21926562, + "handle": "Tester123", + "userId": 21926562, + "deletedBy": null, + "createdAt": "2021-01-12T10:58:26.237Z", + "firstName": "F_NAME", + "createdBy": 21926562, + "isPrimary": false, + "id": 13833, + "projectId": 16893, + "email": "email@domain.com.z", + "updatedAt": "2021-01-12T10:58:26.237Z", + }, + ] startDate: type: string format: date-time @@ -2398,16 +3572,16 @@ components: weeklyCost: type: number format: decimal - example: 5000.50 + example: 5000.50 description: "The average weekly cost" totalPositions: type: integer - description: 'The sum of number of positions opening in all job' - resources: + description: "The sum of number of positions opening in all job" + resources: type: array description: "The rosources that are assigned" items: - $ref: '#/components/schemas/ResourceUserInfo' + $ref: "#/components/schemas/ResourceUserInfo" User: properties: id: @@ -2424,13 +3598,13 @@ components: example: "https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg" description: "The user avatar." firstName: - type: string - example: 'Tony' - description: 'The first name of user' + type: string + example: "Tony" + description: "The first name of user" lastName: type: string - example: 'J' - description: 'The last name of user' + example: "J" + description: "The last name of user" ResourceUserInfo: properties: id: @@ -2451,13 +3625,13 @@ components: example: "https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg" description: "The user avatar." firstName: - type: string - example: 'Tony' - description: 'The first name of user' + type: string + example: "Tony" + description: "The first name of user" lastName: type: string - example: 'J' - description: 'The last name of user' + example: "J" + description: "The last name of user" TeamDetail: properties: id: @@ -2473,13 +3647,46 @@ components: items: type: object description: "The invites of the project" - example: [{"createdAt": "2021-02-08T09:21:00.885Z", "createdBy": 40159127, "deletedBy": null, "email": null, "id": 3008, "projectId": 16819, "role": "customer", "status": "pending", "updatedAt": "2021-02-08T09:21:00.885Z", "updatedBy": 40159127, "userId": 40153913}] + example: + [ + { + "createdAt": "2021-02-08T09:21:00.885Z", + "createdBy": 40159127, + "deletedBy": null, + "email": null, + "id": 3008, + "projectId": 16819, + "role": "customer", + "status": "pending", + "updatedAt": "2021-02-08T09:21:00.885Z", + "updatedBy": 40159127, + "userId": 40153913, + }, + ] members: type: array items: type: object description: "The members of the project" - example: [{"lastName": "L_NAME", "role": "customer", "updatedBy": 21926562, "handle": "Tester123", "userId": 21926562, "deletedBy": null, "createdAt": "2021-01-12T10:58:26.237Z", "firstName": "F_NAME", "createdBy": 21926562, "isPrimary": false, "id": 13833, "projectId": 16893, "email": "email@domain.com.z", "updatedAt": "2021-01-12T10:58:26.237Z"}] + example: + [ + { + "lastName": "L_NAME", + "role": "customer", + "updatedBy": 21926562, + "handle": "Tester123", + "userId": 21926562, + "deletedBy": null, + "createdAt": "2021-01-12T10:58:26.237Z", + "firstName": "F_NAME", + "createdBy": 21926562, + "isPrimary": false, + "id": 13833, + "projectId": 16893, + "email": "email@domain.com.z", + "updatedAt": "2021-01-12T10:58:26.237Z", + }, + ] startDate: type: string format: date-time @@ -2493,14 +3700,14 @@ components: weeklyCost: type: number format: decimal - example: 5000.50 + example: 5000.50 description: "The average weekly cost" - resources: + resources: type: array description: "The rosources that are assigned" items: - allOf: - - $ref: '#/components/schemas/ResourceUserInfo' + allOf: + - $ref: "#/components/schemas/ResourceUserInfo" type: object properties: customerRate: @@ -2508,10 +3715,10 @@ components: format: float example: 13 description: "The customer rate." - skills: + skills: type: array items: - $ref: '#/components/schemas/Skill' + $ref: "#/components/schemas/Skill" jobId: type: string format: uuid @@ -2526,22 +3733,22 @@ components: format: date-time example: "2020-09-27T04:17:23.131Z" description: "Resource end date." - - jobs: + + jobs: type: array description: "The jobs which are opened" items: - $ref: '#/components/schemas/JobForTeam' - Skill: + $ref: "#/components/schemas/JobForTeam" + Skill: type: object properties: id: type: string format: uuid description: "The skill id." - name: + name: type: string - example: 'React' + example: "React" description: The skill name. UbahnSkill: type: object @@ -2604,13 +3811,13 @@ components: description: "The number of positions for the job." rateType: type: string - enum: ['hourly', 'daily', 'weekly', 'monthly'] + enum: ["hourly", "daily", "weekly", "monthly"] description: "The rate type of the job." skills: type: array description: "The skills." items: - $ref: '#/components/schemas/Skill' + $ref: "#/components/schemas/Skill" customerRate: type: integer format: float @@ -2618,7 +3825,7 @@ components: description: "The customer rate." status: type: string - enum: ['sourcing', 'in-review', 'assigned', 'closed', 'cancelled'] + enum: ["sourcing", "in-review", "assigned", "closed", "cancelled"] description: "The job status." JobDetail: type: object @@ -2634,8 +3841,8 @@ components: candidates: type: array items: - allOf: - - $ref: '#/components/schemas/User' + allOf: + - $ref: "#/components/schemas/User" type: object properties: id: @@ -2646,18 +3853,27 @@ components: type: string format: uuid description: "User id." - resume: + resume: type: string format: url - description: 'The link for the resume that can be downloaded' + description: "The link for the resume that can be downloaded" status: type: string - enum: ['open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview', 'topcoder-rejected'] + enum: + [ + "open", + "selected", + "shortlist", + "rejected", + "cancelled", + "interview", + "topcoder-rejected", + ] description: "The job candidate status." - skills: - type: array - items: - $ref: '#/components/schemas/Skill' + skills: + type: array + items: + $ref: "#/components/schemas/Skill" TeamEmailRequestBody: type: object properties: @@ -2667,7 +3883,12 @@ components: example: "team-issue-report" data: type: object - example: {"projectName": "TaaS Project Name", "projectId": 12345, "reportText": "I have issue with ..."} + example: + { + "projectName": "TaaS Project Name", + "projectId": 12345, + "reportText": "I have issue with ...", + } description: "Arbitrary data to feed the specified template" AddMembersRequestBody: properties: @@ -2684,14 +3905,14 @@ components: items: type: string description: "the email of a member" - example: 'xxx@xxx.com' + example: "xxx@xxx.com" AddMembersResponseBody: properties: success: type: array description: "The members created." items: - $ref: '#/components/schemas/ProjectMember' + $ref: "#/components/schemas/ProjectMember" failed: type: array description: "The emails." @@ -2716,13 +3937,185 @@ components: email: type: string description: "the email of a member" - example: 'xxx@xxx.com' + example: "xxx@xxx.com" ProjectMember: type: object - example: {"id": 14329, "userId": 40159097, "role": "customer", "createdAt": "2021-02-24T12:34:45.074Z", "updatedAt": "2021-02-24T12:34:45.075Z", "createdBy": -101, "updatedBy": -101, "handle": "tester1234", "photoURL": null, "workingHourStart": "9:00", "workingHourEnd": "17:00", "timeZone": "Asia/Kolkata", "email": "sathya.jayabal@gmail.com"} + example: + { + "id": 14329, + "userId": 40159097, + "role": "customer", + "createdAt": "2021-02-24T12:34:45.074Z", + "updatedAt": "2021-02-24T12:34:45.075Z", + "createdBy": -101, + "updatedBy": -101, + "handle": "tester1234", + "photoURL": null, + "workingHourStart": "9:00", + "workingHourEnd": "17:00", + "timeZone": "Asia/Kolkata", + "email": "xxx@xxx.com", + } ProjectMemberInvite: type: object - example: {"createdAt": "2021-02-24T11:02:12.673Z", "deletedAt": null, "role": "customer", "updatedBy": -101, "createdBy": -101, "id": 3686, "projectId": 16705, "userId": 23008602, "email": null, "deletedBy": null, "updatedAt": "2021-02-24T11:02:12.674Z", "status": "pending"} + example: + { + "createdAt": "2021-02-24T11:02:12.673Z", + "deletedAt": null, + "role": "customer", + "updatedBy": -101, + "createdBy": -101, + "id": 3686, + "projectId": 16705, + "userId": 23008602, + "email": null, + "deletedBy": null, + "updatedAt": "2021-02-24T11:02:12.674Z", + "status": "pending", + } + UbahnUser: + type: object + example: + { + "lastName": "DeLaurentis", + "updatedBy": "tcAdmin", + "achievements": + [ + { + "certifierId": "certifierId", + "updatedBy": "tcAdmin", + "createdBy": "tc-user", + "certifiedDate": "2020-05-04T07:36:28.036Z", + "created": "2020-05-13T08:44:27.244Z", + "name": "Topcoder", + "id": "a49e1013-fd42-4c08-bc12-492510cadb96", + "achievementsProviderId": "ce05133f-129e-484d-9ef9-72bf51ff81f9", + "uri": "http://www.google.com/xx", + "updated": "2021-01-05T10:58:32.429Z", + "userId": "0bcb0d86-09bb-410a-b2b1-fba90d1a7699", + "achievementprovider": + { + "updatedBy": "tcAdmin", + "createdBy": "tc-user", + "created": "2020-05-13T08:42:41.877Z", + "name": "achievementsProviders_02", + "id": "ce05133f-129e-484d-9ef9-72bf51ff81f9", + "updated": "2021-01-05T10:58:32.341Z", + }, + }, + ], + "created": "2020-05-05T10:18:03.882Z", + "handle": "lazybaer", + "skills": + [ + { + "certifierId": null, + "skillId": "d67f35c3-fa42-4866-a0f9-0a4b84fcf4a9", + "updatedBy": "tcAdmin", + "createdBy": "lazybaer", + "certifiedDate": null, + "created": "2020-10-23T16:22:11.208Z", + "skill": + { + "updatedBy": "tcAdmin", + "skillprovider": + { + "updatedBy": "tcAdmin", + "createdBy": "TonyJ", + "created": "2020-08-31T12:30:00.543Z", + "name": "Wipro Digital", + "id": "26fb37b1-5f9f-4727-baa9-f3c87de84ab1", + "updated": "2021-01-05T10:58:32.836Z", + }, + "createdBy": "0", + "created": "2020-09-01T21:59:21.554Z", + "skillProviderId": "26fb37b1-5f9f-4727-baa9-f3c87de84ab1", + "name": "GitHub", + "externalId": null, + "id": "d67f35c3-fa42-4866-a0f9-0a4b84fcf4a9", + "uri": null, + "updated": "2021-01-05T10:58:33.332Z", + }, + "metricValue": null, + "id": "8a84c1b4-1884-4a3c-90b2-eb86bf469bb6", + "updated": "2021-01-05T10:58:34.080Z", + "userId": "0bcb0d86-09bb-410a-b2b1-fba90d1a7699", + }, + ], + "firstName": "Christopher", + "externalProfiles": + [ + { + "organizationId": "0d2320f9-be61-4ba4-973e-edc3bb682a69", + "updatedBy": "tcAdmin", + "createdBy": "TonyJ", + "isInactive": false, + "created": "2020-08-31T12:30:38.495Z", + "organization": + { + "updatedBy": "tcAdmin", + "createdBy": "TonyJ", + "created": "2020-08-31T12:29:58.081Z", + "name": "Wipro Digital", + "skillProviders": + [ + { + "organizationId": "0d2320f9-be61-4ba4-973e-edc3bb682a69", + "updatedBy": "tcAdmin", + "createdBy": "TonyJ", + "created": "2020-08-31T12:30:08.410Z", + "skillProviderId": "26fb37b1-5f9f-4727-baa9-f3c87de84ab1", + "id": "5b26cdd3-fe68-4b30-85c5-ceaf280bd688", + "updated": "2021-01-05T10:58:32.919Z", + }, + ], + "id": "0d2320f9-be61-4ba4-973e-edc3bb682a69", + "updated": "2021-01-05T10:58:32.261Z", + }, + "externalId": "8547899", + "id": "870af97b-8c3b-4659-92d6-cac126bbe9de", + "uri": null, + "updated": "2021-01-05T10:58:32.724Z", + "userId": "0bcb0d86-09bb-410a-b2b1-fba90d1a7699", + }, + ], + "createdBy": "tc-Copilot", + "attributes": + [ + { + "attributeId": "d709276a-80c3-491c-9b29-a4f065b2a56f", + "updatedBy": "tcAdmin", + "createdBy": "tc-Admin", + "created": "2020-05-13T08:19:13.709Z", + "id": "21de9324-900d-41ea-b127-f297dfb9a873", + "attribute": + { + "updatedBy": "tcAdmin", + "attributegroup": + { + "organizationId": "36ed815b-3da1-49f1-a043-aaed0a4e81ad", + "updatedBy": "tc-Admin", + "createdBy": "tc-Admin", + "created": "2020-05-13T07:15:01.215Z", + "name": "group 03", + "id": "84634bbd-8191-40cf-a03e-9962d7e39fda", + "updated": "2020-05-13T07:16:20.636Z", + }, + "createdBy": "tc-Admin", + "created": "2020-05-13T07:32:03.128Z", + "name": "Billing Account", + "id": "d709276a-80c3-491c-9b29-a4f065b2a56f", + "attributeGroupId": "84634bbd-8191-40cf-a03e-9962d7e39fda", + "updated": "2021-01-05T10:58:32.604Z", + }, + "value": "74314457", + "updated": "2021-01-05T10:58:33.739Z", + "userId": "0bcb0d86-09bb-410a-b2b1-fba90d1a7699", + }, + ], + "id": "0bcb0d86-09bb-410a-b2b1-fba90d1a7699", + "updated": "2021-01-05T10:58:32.113Z", + } Error: required: - message diff --git a/docs/topcoder-bookings.postman_environment.json b/docs/topcoder-bookings.postman_environment.json index 52dd7275..fc326e86 100644 --- a/docs/topcoder-bookings.postman_environment.json +++ b/docs/topcoder-bookings.postman_environment.json @@ -1,5 +1,5 @@ { - "id": "a7cb1c6e-c710-49c3-ad58-db7536c85944", + "id": "8df2004f-35bd-439c-93b2-0d999d88ec99", "name": "topcoder-bookings", "values": [ { @@ -7,21 +7,6 @@ "value": "http://localhost:3000/api/v5", "enabled": true }, - { - "key": "jobId", - "value": "", - "enabled": true - }, - { - "key": "jobCandidateId", - "value": "", - "enabled": true - }, - { - "key": "resourceBookingId", - "value": "", - "enabled": true - }, { "key": "token_administrator", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjIxNDc0ODM2NDgsInVzZXJJZCI6IjQwMTUyODU2IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.PKv0QrMCPf0-ZPjv4PGWT7eXne54m7i9YX9eq-fceMU", @@ -38,13 +23,13 @@ "enabled": true }, { - "key": "token_connect_manager_pshahcopmanag2", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL3RvcGNvZGVyLWRldi5jb20vcm9sZXMiOlsiQnVzaW5lc3MgVXNlciIsIlRvcGNvZGVyIFVzZXIiLCJDb25uZWN0IENvcGlsb3QgTWFuYWdlciIsIkNvbm5lY3QgTWFuYWdlciJdLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcklkIjoiODg3NzQ0ODkiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vaGFuZGxlIjoicHNoYWhjb3BtYW5hZzIiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcl9pZCI6ImF1dGgwfDg4Nzc0NDg5IiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL3Rjc3NvIjoiODg3NzQ0ODl8ODdhZDNiNjNiZGZjMmYyNjczNGJiMDIzMTM2YWEzM2NhYWY5MzdiNzdhZmQyYjE3YzljMWY3ZWVkZWI4IiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL2FjdGl2ZSI6dHJ1ZSwibmlja25hbWUiOiJwc2hhaGNvcG1hbmFnMiIsIm5hbWUiOiJtYXhjZWVtK3RjK3BzaGFoY29wbWFuYWcyQGdtYWlsLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8wZDY1NWNlZDM4NTFiM2JmY2I1Y2Y3Y2U3NjY0ODQwNj9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRm1hLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDIxLTAxLTAyVDEyOjM3OjAxLjE2MFoiLCJlbWFpbCI6Im1heGNlZW0rdGMrcHNoYWhjb3BtYW5hZzJAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXV0aC50b3Bjb2Rlci1kZXYuY29tLyIsInN1YiI6ImF1dGgwfDg4Nzc0NDg5IiwiYXVkIjoiQlhXWFVXbmlsVlVQZE4wMXQyU2UyOVR3MlpZTkdadkgiLCJpYXQiOjE2MDk1OTEwMjQsImV4cCI6MjE0NzQ4MzY0OCwibm9uY2UiOiJaVmhCV1dKbU5GbFlOa0pGU0ZWSU9VSkZTbFIrYkhoVVVEYzJmak41UkVWcFFuWkRWSFZUVlVKU1RRPT0ifQ.G-wrxaqoRH9GQS9cjqX93nRoH91tn-wPW1j_MA42lCY", + "key": "token_member", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik5VSkZORGd4UlRVME5EWTBOVVkzTlRkR05qTXlRamxETmpOQk5UYzVRVUV3UlRFeU56TTJRUSJ9.eyJodHRwczovL3RvcGNvZGVyLWRldi5jb20vcm9sZXMiOlsiVG9wY29kZXIgVXNlciJdLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcklkIjoiODU0Nzg5OSIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS9oYW5kbGUiOiJwc2hhaF9tYW5hZ2VyIiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL3VzZXJfaWQiOiJhdXRoMHw0MDE1Mjg1NiIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS90Y3NzbyI6IjQwMTUyODU2fDgxMzRmNDhlYmUxMWE4NDhhMzc1OWU1ZWY5ZTkyZjIxNDY5MmUyMTEzMDQwYzgyYjVkOGY1ODFjNmRmY2NjODgiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vYWN0aXZlIjp0cnVlLCJuaWNrbmFtZSI6InBzaGFoX21hbmFnZXIiLCJuYW1lIjoidmlrYXMuYWdhcndhbCtwc2hhaF9tYW5hZ2VyQHRvcGNvZGVyLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci85MmFmYjJmMGVkNTJmZGZhZTFmMzcxMDIxYWU2NTAxMz9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRnZpLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDIwLTEwLTI0VDA4OjI4OjI0LjE4NFoiLCJlbWFpbCI6InZpa2FzLmFnYXJ3YWwrcHNoYWhfbWFuYWdlckB0b3Bjb2Rlci5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnRvcGNvZGVyLWRldi5jb20vIiwic3ViIjoiYXV0aDB8NDAxNTI4NTYiLCJhdWQiOiJCWFdYVVduaWxWVVBkTjAxdDJTZTI5VHcyWllOR1p2SCIsImlhdCI6MTYwMzU0MzMzOCwiZXhwIjozMzE2MDQ1MjczOCwibm9uY2UiOiJSMUEyY3pZdVZUWm1ialpIUkc5MlZsOURTVUo2VWxsdlFYYzNSSGg1UzNaV2RXWkRjRE5YTUVaMVh3PT0ifQ.HbAisH30DLcbFNQeIifSzk1yhDmlGHNpPi9LSZbAowo", "enabled": true }, { - "key": "token_member", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik5VSkZORGd4UlRVME5EWTBOVVkzTlRkR05qTXlRamxETmpOQk5UYzVRVUV3UlRFeU56TTJRUSJ9.eyJodHRwczovL3RvcGNvZGVyLWRldi5jb20vcm9sZXMiOlsiVG9wY29kZXIgVXNlciJdLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcklkIjoiODU0Nzg5OSIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS9oYW5kbGUiOiJwc2hhaF9tYW5hZ2VyIiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL3VzZXJfaWQiOiJhdXRoMHw0MDE1Mjg1NiIsImh0dHBzOi8vdG9wY29kZXItZGV2LmNvbS90Y3NzbyI6IjQwMTUyODU2fDgxMzRmNDhlYmUxMWE4NDhhMzc1OWU1ZWY5ZTkyZjIxNDY5MmUyMTEzMDQwYzgyYjVkOGY1ODFjNmRmY2NjODgiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vYWN0aXZlIjp0cnVlLCJuaWNrbmFtZSI6InBzaGFoX21hbmFnZXIiLCJuYW1lIjoidmlrYXMuYWdhcndhbCtwc2hhaF9tYW5hZ2VyQHRvcGNvZGVyLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci85MmFmYjJmMGVkNTJmZGZhZTFmMzcxMDIxYWU2NTAxMz9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRnZpLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDIwLTEwLTI0VDA4OjI4OjI0LjE4NFoiLCJlbWFpbCI6InZpa2FzLmFnYXJ3YWwrcHNoYWhfbWFuYWdlckB0b3Bjb2Rlci5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnRvcGNvZGVyLWRldi5jb20vIiwic3ViIjoiYXV0aDB8NDAxNTI4NTYiLCJhdWQiOiJCWFdYVVduaWxWVVBkTjAxdDJTZTI5VHcyWllOR1p2SCIsImlhdCI6MTYwMzU0MzMzOCwiZXhwIjozMzE2MDQ1MjczOCwibm9uY2UiOiJSMUEyY3pZdVZUWm1ialpIUkc5MlZsOURTVUo2VWxsdlFYYzNSSGg1UzNaV2RXWkRjRE5YTUVaMVh3PT0ifQ.HbAisH30DLcbFNQeIifSzk1yhDmlGHNpPi9LSZbAowo", + "key": "token_connect_manager_pshahcopmanag2", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL3RvcGNvZGVyLWRldi5jb20vcm9sZXMiOlsiQnVzaW5lc3MgVXNlciIsIlRvcGNvZGVyIFVzZXIiLCJDb25uZWN0IENvcGlsb3QgTWFuYWdlciIsIkNvbm5lY3QgTWFuYWdlciJdLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcklkIjoiODg3NzQ0ODkiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vaGFuZGxlIjoicHNoYWhjb3BtYW5hZzIiLCJodHRwczovL3RvcGNvZGVyLWRldi5jb20vdXNlcl9pZCI6ImF1dGgwfDg4Nzc0NDg5IiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL3Rjc3NvIjoiODg3NzQ0ODl8ODdhZDNiNjNiZGZjMmYyNjczNGJiMDIzMTM2YWEzM2NhYWY5MzdiNzdhZmQyYjE3YzljMWY3ZWVkZWI4IiwiaHR0cHM6Ly90b3Bjb2Rlci1kZXYuY29tL2FjdGl2ZSI6dHJ1ZSwibmlja25hbWUiOiJwc2hhaGNvcG1hbmFnMiIsIm5hbWUiOiJtYXhjZWVtK3RjK3BzaGFoY29wbWFuYWcyQGdtYWlsLmNvbSIsInBpY3R1cmUiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8wZDY1NWNlZDM4NTFiM2JmY2I1Y2Y3Y2U3NjY0ODQwNj9zPTQ4MCZyPXBnJmQ9aHR0cHMlM0ElMkYlMkZjZG4uYXV0aDAuY29tJTJGYXZhdGFycyUyRm1hLnBuZyIsInVwZGF0ZWRfYXQiOiIyMDIxLTAxLTAyVDEyOjM3OjAxLjE2MFoiLCJlbWFpbCI6Im1heGNlZW0rdGMrcHNoYWhjb3BtYW5hZzJAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXV0aC50b3Bjb2Rlci1kZXYuY29tLyIsInN1YiI6ImF1dGgwfDg4Nzc0NDg5IiwiYXVkIjoiQlhXWFVXbmlsVlVQZE4wMXQyU2UyOVR3MlpZTkdadkgiLCJpYXQiOjE2MDk1OTEwMjQsImV4cCI6MjE0NzQ4MzY0OCwibm9uY2UiOiJaVmhCV1dKbU5GbFlOa0pGU0ZWSU9VSkZTbFIrYkhoVVVEYzJmak41UkVWcFFuWkRWSFZUVlVKU1RRPT0ifQ.G-wrxaqoRH9GQS9cjqX93nRoH91tn-wPW1j_MA42lCY", "enabled": true }, { @@ -58,23 +43,8 @@ "enabled": true }, { - "key": "projectId", - "value": "111", - "enabled": true - }, - { - "key": "project_id_16718", - "value": "16718", - "enabled": true - }, - { - "key": "project_id_16843", - "value": "16843", - "enabled": true - }, - { - "key": "jobIdCreatedByMember", - "value": "", + "key": "token_m2m_create_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.m-tHt9ABFj5KqzWYbLNxufVL4QvNw_y4j7w-Pj9l5_E", "enabled": true }, { @@ -82,11 +52,6 @@ "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9icyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.l4fH_SGhhbP8kcQoOJhhQW0eRGwC3wIwuj0_7XGj7Ac", "enabled": true }, - { - "key": "token_m2m_create_job", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.m-tHt9ABFj5KqzWYbLNxufVL4QvNw_y4j7w-Pj9l5_E", - "enabled": true - }, { "key": "token_m2m_update_job", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.AM9C6kPZmtQVN-6GtbKeMIiQIZqRk5nOcPuciClZKdY", @@ -103,13 +68,13 @@ "enabled": true }, { - "key": "token_m2m_read_job_candidate", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9iQ2FuZGlkYXRlcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.N-5rUvF8gKHqs3rSCjlbsa6GJ9SPgJ66ZQlGYuImQXQ", + "key": "token_m2m_create_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.SXQY7145ceuDQd8YPAv4ePyaF1JRnHtVGy1kIhzCfPk", "enabled": true }, { - "key": "token_m2m_create_job_candidate", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.SXQY7145ceuDQd8YPAv4ePyaF1JRnHtVGy1kIhzCfPk", + "key": "token_m2m_read_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9iQ2FuZGlkYXRlcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.N-5rUvF8gKHqs3rSCjlbsa6GJ9SPgJ66ZQlGYuImQXQ", "enabled": true }, { @@ -128,13 +93,13 @@ "enabled": true }, { - "key": "token_m2m_read_resource_booking", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtcmVzb3VyY2VCb29raW5ncyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.tQEMwMS7z7S1q_9vyVCvhlKKRInZ4U21KdE1lQIenjo", + "key": "token_m2m_create_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.mE4x9DtPvjVKCib3S9qykmwAr1NsloT0ozQVOPcSdMU", "enabled": true }, { - "key": "token_m2m_create_resource_booking", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.mE4x9DtPvjVKCib3S9qykmwAr1NsloT0ozQVOPcSdMU", + "key": "token_m2m_read_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtcmVzb3VyY2VCb29raW5ncyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.tQEMwMS7z7S1q_9vyVCvhlKKRInZ4U21KdE1lQIenjo", "enabled": true }, { @@ -157,23 +122,228 @@ "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtdGVhbXMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.LKd9krhA2ErAMPqLR6dEeWPG0u0JedsysrkZwvAVSMs", "enabled": true }, + { + "key": "projectId", + "value": "111", + "enabled": true + }, + { + "key": "project_id_16718", + "value": "16718", + "enabled": true + }, + { + "key": "project_id_16843", + "value": "16843", + "enabled": true + }, + { + "key": "project_id_17234", + "value": "17234", + "enabled": true + }, + { + "key": "jobId", + "value": "", + "enabled": true + }, { "key": "jobIdCreatedByM2M", - "value": "47430794-8d89-42a4-947b-341b3fe75031", + "value": "", + "enabled": true + }, + { + "key": "jobIdCreatedByMember", + "value": "", + "enabled": true + }, + { + "key": "jobCandidateId", + "value": "", "enabled": true }, { "key": "jobCandidateIdCreatedByM2M", - "value": "bdc13c45-40a2-4597-9b21-4b572a1faf25", + "value": "", + "enabled": true + }, + { + "key": "resourceBookingId", + "value": "", "enabled": true }, { "key": "resourceBookingIdCreatedByM2M", - "value": "083ddc0e-710e-45f3-b4d3-1f70bf3d8713", + "value": "", + "enabled": true + }, + { + "key": "workPeriodId", + "value": "", + "enabled": true + }, + { + "key": "workPeriodIdCreatedByM2M", + "value": "", + "enabled": true + }, + { + "key": "token_m2m_create_work_period", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy13b3JrUGVyaW9kcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.tgKxTrlI8bu6CVFk4-kFB1gKHL-L6X8akKYYREjZiSE", + "enabled": true + }, + { + "key": "token_m2m_read_work_period", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtd29ya1BlcmlvZHMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.y0-mysWkSf6YnUw9jKhxzg65ngPWNhfXzGQGCVWhXrk", + "enabled": true + }, + { + "key": "token_m2m_read_work_period_and_payment", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtd29ya1BlcmlvZHMgcmVhZDp0YWFzLXdvcmtQZXJpb2RQYXltZW50cyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.9BEieQDP5totqvwriBozy8cgFQRiLXQ6xA6IJT9SD8s", + "enabled": true + }, + { + "key": "token_m2m_update_work_period", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy13b3JrUGVyaW9kcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.TU4vUcrQylzIyB6hDMqqC5NucpDSRMHWd-PZ6uW_lEc", + "enabled": true + }, + { + "key": "token_m2m_delete_work_period", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy13b3JrUGVyaW9kcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.gKWTDiVYowiTgUV9n4z2O9W-BksDgVThALR-pZ8szyY", + "enabled": true + }, + { + "key": "token_m2m_all_work_period", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy13b3JrUGVyaW9kcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.0gEgjGsG4ftTOlfN1bTZQXw3YIvxBiCGJEBzD0bmyUE", + "enabled": true + }, + { + "key": "token_m2m_all_work_period_and_payment", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy13b3JrUGVyaW9kcyBhbGw6dGFhcy13b3JrUGVyaW9kUGF5bWVudHMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.3y9Rij_PH5V9DgX5SxMKN6_RaxtbpDGPz-rTbzdVM4Q", + "enabled": true + }, + { + "key": "token_m2m_create_work_period_payment", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy13b3JrUGVyaW9kUGF5bWVudHMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.9XELn_QXS6zk8XEvusiIe42xddUO29oW0QbqljOlj18", + "enabled": true + }, + { + "key": "token_m2m_read_work_period_payment", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtd29ya1BlcmlvZFBheW1lbnRzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.5mFoV4Lg49AuEpteoVLffgyT8Gwgp_YaOvBjfUKjK_4", + "enabled": true + }, + { + "key": "token_m2m_update_work_period_payment", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy13b3JrUGVyaW9kUGF5bWVudHMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.-J0_bWiOoUOWY7rHrx5ETjvXZLzXp77PR8ErehA_y50", + "enabled": true + }, + { + "key": "token_m2m_all_work_period_payment", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy13b3JrUGVyaW9kUGF5bWVudHMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.ut5vdW-124nBshaeGBvg4mCue4XlRljWlV7OneJk4i4", + "enabled": true + }, + { + "key": "job_id_created_by_administrator", + "value": "", + "enabled": true + }, + { + "key": "resource_bookings_id_created_by_administrator", + "value": "", + "enabled": true + }, + { + "key": "workPeriodId_created_by_administrator", + "value": "", + "enabled": true + }, + { + "key": "job_id_created_by_member", + "value": "", + "enabled": true + }, + { + "key": "resource_booking_id_created_by_member", + "value": "", + "enabled": true + }, + { + "key": "resource_booking_id_created_for_member", + "value": "", + "enabled": true + }, + { + "key": "workPeriodId_created_for_member", + "value": "", + "enabled": true + }, + { + "key": "resource_booking_id_created_for_connect_manager", + "value": "", + "enabled": true + }, + { + "key": "job_id_created_by_connect_manager", + "value": "", + "enabled": true + }, + { + "key": "workPeriodId_created_for_connect_manager", + "value": "", + "enabled": true + }, + { + "key": "job_candidate_id_created_by_administrator", + "value": "", + "enabled": true + }, + { + "key": "workPeriodPaymentId", + "value": "", + "enabled": true + }, + { + "key": "workPeriodPaymentIdCreatedByM2M", + "value": "", + "enabled": true + }, + { + "key": "workPeriodPaymentId_created_by_administrator", + "value": "", + "enabled": true + }, + { + "key": "job_id_created_for_member", + "value": "", + "enabled": true + }, + { + "key": "resource_bookings_id_created_for_member", + "value": "", + "enabled": true + }, + { + "key": "workPeriodPaymentId_created_for_member", + "value": "", + "enabled": true + }, + { + "key": "job_id_created_for_connect_manager", + "value": "", + "enabled": true + }, + { + "key": "resource_bookings_id_created_for_connect_manager", + "value": "", + "enabled": true + }, + { + "key": "workPeriodPaymentId_created_for_connect_manager", + "value": "", "enabled": true } ], "_postman_variable_scope": "environment", - "_postman_exported_at": "2020-12-04T12:09:30.809Z", - "_postman_exported_using": "Postman/7.29.0" -} + "_postman_exported_at": "2021-04-09T20:23:10.418Z", + "_postman_exported_using": "Postman/8.2.1" +} \ No newline at end of file diff --git a/local/kafka-client/Dockerfile b/local/kafka-client/Dockerfile index e34a3ae6..64b15b36 100644 --- a/local/kafka-client/Dockerfile +++ b/local/kafka-client/Dockerfile @@ -1,4 +1,4 @@ -From wurstmeister/kafka +FROM wurstmeister/kafka WORKDIR /app/ COPY topics.txt . COPY create-topics.sh . diff --git a/local/kafka-client/topics.txt b/local/kafka-client/topics.txt index 7bf08bc8..dc37db59 100644 --- a/local/kafka-client/topics.txt +++ b/local/kafka-client/topics.txt @@ -1,10 +1,16 @@ taas.job.create taas.jobcandidate.create taas.resourcebooking.create +taas.workperiod.create +taas.workperiodpayment.create taas.job.update taas.jobcandidate.update taas.resourcebooking.update +taas.workperiod.update +taas.workperiodpayment.update taas.job.delete taas.jobcandidate.delete taas.resourcebooking.delete +taas.workperiod.delete +taas.workperiodpayment.delete external.action.email diff --git a/migrations/2021-01-04-make-some-resouce-booking-fields-optional.js b/migrations/2021-01-04-make-some-resouce-booking-fields-optional.js index 5ae7e66d..f8313177 100644 --- a/migrations/2021-01-04-make-some-resouce-booking-fields-optional.js +++ b/migrations/2021-01-04-make-some-resouce-booking-fields-optional.js @@ -1,3 +1,5 @@ +const config = require('config') + /* * Make ResourceBooking fields startDate, endDate, memberRate and customerRate optional. */ @@ -16,3 +18,48 @@ module.exports = { )) } } + +module.exports = { + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'start_date', + { type: Sequelize.DATE, allowNull: true }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATE, allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'member_rate', + { type: Sequelize.FLOAT, allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'customer_rate', + { type: Sequelize.FLOAT, allowNull: true } + , { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + }, + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'start_date', + { type: Sequelize.DATE, allowNull: false }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATE, allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'member_rate', + { type: Sequelize.FLOAT, allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'customer_rate', + { type: Sequelize.FLOAT, allowNull: false } + , { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + } +} diff --git a/migrations/2021-01-06-job-add-title-field.js b/migrations/2021-01-06-job-add-title-field.js index 6832332e..3423ed83 100644 --- a/migrations/2021-01-06-job-add-title-field.js +++ b/migrations/2021-01-06-job-add-title-field.js @@ -1,18 +1,28 @@ +const config = require('config') + /* * Add title field to the Job model. */ module.exports = { - up: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.jobs ADD title VARCHAR(64)'), - queryInterface.sequelize.query('UPDATE bookings.jobs SET title=description WHERE title is NULL'), - queryInterface.sequelize.query('ALTER TABLE bookings.jobs ALTER COLUMN title SET NOT NULL') - ]) + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.addColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'title', + { type: Sequelize.STRING(64) }, + { transaction }) + await queryInterface.sequelize.query(`UPDATE ${config.DB_SCHEMA_NAME}.jobs SET title = description`, + { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'title', + { type: Sequelize.STRING(64), allowNull: false } + , { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } }, - down: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.jobs DROP title') - ]) + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'title') } } diff --git a/migrations/2021-01-07-job-candidate-add-external-id-and-resume-fields.js b/migrations/2021-01-07-job-candidate-add-external-id-and-resume-fields.js index 6ca47bba..dbd04397 100644 --- a/migrations/2021-01-07-job-candidate-add-external-id-and-resume-fields.js +++ b/migrations/2021-01-07-job-candidate-add-external-id-and-resume-fields.js @@ -1,18 +1,36 @@ +const config = require('config') + /* * Add externalId and resume fields to the JobCandidate model. */ module.exports = { - up: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.job_candidates ADD external_id VARCHAR(255)'), - queryInterface.sequelize.query('ALTER TABLE bookings.job_candidates ADD resume VARCHAR(2048)') - ]) + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.addColumn({ tableName: 'job_candidates', schema: config.DB_SCHEMA_NAME }, 'external_id', + { type: Sequelize.STRING(255) }, + { transaction }) + await queryInterface.addColumn({ tableName: 'job_candidates', schema: config.DB_SCHEMA_NAME }, 'resume', + { type: Sequelize.STRING(2048) }, + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } }, - down: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.job_candidates DROP external_id'), - queryInterface.sequelize.query('ALTER TABLE bookings.job_candidates DROP resume') - ]) + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.removeColumn({ tableName: 'job_candidates', schema: config.DB_SCHEMA_NAME }, 'resume', + { transaction }) + await queryInterface.removeColumn({ tableName: 'job_candidates', schema: config.DB_SCHEMA_NAME }, 'external_id', + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } } } diff --git a/migrations/2021-01-09-make-some-job-fields-optional.js b/migrations/2021-01-09-make-some-job-fields-optional.js index 88a7fc32..9bd224e4 100644 --- a/migrations/2021-01-09-make-some-job-fields-optional.js +++ b/migrations/2021-01-09-make-some-job-fields-optional.js @@ -1,26 +1,68 @@ +const config = require('config') + /* * Make Job fields externalId, description, startDate, endDate, resourceType, rateType and workload optional. */ -const targetFields = [ - 'external_id', - 'description', - 'start_date', - 'end_date', - 'resource_type', - 'rate_type', - 'workload' -] - module.exports = { - up: queryInterface => { - return Promise.all(targetFields.map(field => - queryInterface.sequelize.query(`ALTER TABLE bookings.jobs ALTER COLUMN ${field} DROP NOT NULL`) - )) + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'external_id', + { type: Sequelize.STRING(255), allowNull: true }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'description', + { type: Sequelize.STRING(255), allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'start_date', + { type: Sequelize.DATE, allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATE, allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'resource_type', + { type: Sequelize.STRING(255), allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'rate_type', + { type: Sequelize.STRING(255), allowNull: true } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'workload', + { type: Sequelize.STRING(45), allowNull: true } + , { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } }, - down: queryInterface => { - return Promise.all(targetFields.map(field => - queryInterface.sequelize.query(`ALTER TABLE bookings.jobs ALTER COLUMN ${field} SET NOT NULL`) - )) + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'external_id', + { type: Sequelize.STRING(255), allowNull: false }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'description', + { type: Sequelize.STRING(255), allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'start_date', + { type: Sequelize.DATE, allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATE, allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'resource_type', + { type: Sequelize.STRING(255), allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'rate_type', + { type: Sequelize.STRING(255), allowNull: false } + , { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'workload', + { type: Sequelize.STRING(45), allowNull: false } + , { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } } } diff --git a/migrations/2021-01-13-make-some-job-fields-longer.js b/migrations/2021-01-13-make-some-job-fields-longer.js index 286fd888..615f97a1 100644 --- a/migrations/2021-01-13-make-some-job-fields-longer.js +++ b/migrations/2021-01-13-make-some-job-fields-longer.js @@ -1,3 +1,5 @@ +const config = require('config') + /* * Make some Job fields longer * title: 64 -> 128 @@ -5,16 +7,34 @@ */ module.exports = { - up: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query(`ALTER TABLE bookings.jobs ALTER COLUMN title TYPE VARCHAR(128)`), - queryInterface.sequelize.query(`ALTER TABLE bookings.jobs ALTER COLUMN description TYPE TEXT`) - ]) + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'title', + { type: Sequelize.STRING(128), allowNull: false }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'description', + { type: Sequelize.TEXT }, + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } }, - down: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query(`ALTER TABLE bookings.jobs ALTER COLUMN title TYPE VARCHAR(64)`), - queryInterface.sequelize.query(`ALTER TABLE bookings.jobs ALTER COLUMN description TYPE VARCHAR(255)`) - ]) + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'title', + { type: Sequelize.STRING(64), allowNull: false }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'description', + { type: Sequelize.STRING(255) }, + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } } } diff --git a/migrations/2021-02-10-job-replace-end-date-with-duration.js b/migrations/2021-02-10-job-replace-end-date-with-duration.js index d7e81096..5630f9e5 100644 --- a/migrations/2021-02-10-job-replace-end-date-with-duration.js +++ b/migrations/2021-02-10-job-replace-end-date-with-duration.js @@ -1,18 +1,40 @@ +const config = require('config') + /* * Replace endData with duration in Job model. */ module.exports = { - up: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.jobs DROP end_date'), - queryInterface.sequelize.query('ALTER TABLE bookings.jobs ADD duration INTEGER') - ]) + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.addColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'duration', + { type: Sequelize.INTEGER }, + { transaction }) + await queryInterface.sequelize.query(`UPDATE ${config.DB_SCHEMA_NAME}.jobs SET duration = DATE_PART('day', end_date - start_date)`, + { transaction }) + await queryInterface.removeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'end_date', + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } }, - down: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.jobs ADD end_date DATE'), - queryInterface.sequelize.query('ALTER TABLE bookings.jobs DROP duration') - ]) + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.addColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATE }, + { transaction }) + await queryInterface.sequelize.query(`UPDATE ${config.DB_SCHEMA_NAME}.jobs SET end_date = start_date + COALESCE(duration,0) * INTERVAL '1 day'`, + { transaction }) + await queryInterface.removeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'duration', + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } } } diff --git a/migrations/2021-02-27-job-add-is-application-page-active-field.js b/migrations/2021-02-27-job-add-is-application-page-active-field.js index 84e548a4..f16f7cea 100644 --- a/migrations/2021-02-27-job-add-is-application-page-active-field.js +++ b/migrations/2021-02-27-job-add-is-application-page-active-field.js @@ -1,19 +1,27 @@ +const config = require('config') + /* * Add isApplicationPageActive field to the Job model. */ module.exports = { - up: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.jobs ADD is_application_page_active BOOLEAN NOT NULL DEFAULT false'), - // this command looks like does nothing, because we already set default value to `null` and this column cannot be `NULL` - // but we keep it as it was tested this way, and it looks harmful - queryInterface.sequelize.query('UPDATE bookings.jobs SET is_application_page_active=false WHERE is_application_page_active is NULL'), - ]) + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.addColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'is_application_page_active', + { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: false }, + { transaction }) + await queryInterface.bulkUpdate({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, + { is_application_page_active: false }, + { is_application_page_active: null }, + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } }, - down: queryInterface => { - return Promise.all([ - queryInterface.sequelize.query('ALTER TABLE bookings.jobs DROP is_application_page_active') - ]) + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn({ tableName: 'jobs', schema: config.DB_SCHEMA_NAME }, 'is_application_page_active') } } diff --git a/migrations/2021-03-30-work-period-table-create.js b/migrations/2021-03-30-work-period-table-create.js new file mode 100644 index 00000000..04a0c66c --- /dev/null +++ b/migrations/2021-03-30-work-period-table-create.js @@ -0,0 +1,119 @@ +const config = require('config') + +/* + * Create work_periods table and reference to the "resource_bookings" table + */ + +module.exports = { + up: async (queryInterface, Sequelize) => { + // because our migration have more than one step we use transaction + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.createTable('work_periods', { + id: { + type: Sequelize.UUID, + primaryKey: true, + allowNull: false, + defaultValue: Sequelize.UUIDV4 + }, + resourceBookingId: { + field: 'resource_booking_id', + type: Sequelize.UUID, + allowNull: false, + references: { + model: { + tableName: 'resource_bookings', + schema: config.DB_SCHEMA_NAME + }, + key: 'id' + }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE' + }, + userHandle: { + field: 'user_handle', + type: Sequelize.STRING(50), + allowNull: false + }, + projectId: { + field: 'project_id', + type: Sequelize.INTEGER, + allowNull: false + }, + startDate: { + field: 'start_date', + type: Sequelize.DATEONLY, + allowNull: false + }, + endDate: { + field: 'end_date', + type: Sequelize.DATEONLY, + allowNull: false + }, + daysWorked: { + field: 'days_worked', + type: Sequelize.INTEGER + }, + memberRate: { + field: 'member_rate', + type: Sequelize.FLOAT + }, + customerRate: { + field: 'customer_rate', + type: Sequelize.FLOAT + }, + paymentStatus: { + field: 'payment_status', + type: Sequelize.STRING(50), + allowNull: false + }, + createdBy: { + field: 'created_by', + type: Sequelize.UUID, + allowNull: false + }, + updatedBy: { + field: 'updated_by', + type: Sequelize.UUID + }, + createdAt: { + field: 'created_at', + type: Sequelize.DATE + }, + updatedAt: { + field: 'updated_at', + type: Sequelize.DATE + }, + deletedAt: { + field: 'deleted_at', + type: Sequelize.DATE + } + }, { + schema: config.DB_SCHEMA_NAME, + transaction + }) + await queryInterface.addIndex( + { + tableName: 'work_periods', + schema: config.DB_SCHEMA_NAME + }, + ['resource_booking_id', 'start_date', 'end_date'], + { + type: 'UNIQUE', + where: { deleted_at: null }, + transaction: transaction + } + ) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable({ + tableName: 'work_periods', + schema: config.DB_SCHEMA_NAME + }) + } +} diff --git a/migrations/2021-04-10-work-period-payment-table-create.js b/migrations/2021-04-10-work-period-payment-table-create.js new file mode 100644 index 00000000..28732637 --- /dev/null +++ b/migrations/2021-04-10-work-period-payment-table-create.js @@ -0,0 +1,76 @@ +/** + * Create work_period_payments table and reference to the "work_periods" table + */ + +const config = require('config') + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('work_period_payments', { + id: { + type: Sequelize.UUID, + primaryKey: true, + allowNull: false, + defaultValue: Sequelize.UUIDV4 + }, + workPeriodId: { + field: 'work_period_id', + type: Sequelize.UUID, + allowNull: false, + references: { + model: { + tableName: 'work_periods', + schema: config.DB_SCHEMA_NAME + }, + key: 'id' + }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE' + }, + challengeId: { + field: 'challenge_id', + type: Sequelize.UUID, + allowNull: false + }, + amount: { + type: Sequelize.DOUBLE + }, + status: { + type: Sequelize.ENUM( + 'completed', + 'cancelled' + ), + allowNull: false + }, + createdBy: { + field: 'created_by', + type: Sequelize.UUID, + allowNull: false + }, + updatedBy: { + field: 'updated_by', + type: Sequelize.UUID + }, + createdAt: { + field: 'created_at', + type: Sequelize.DATE + }, + updatedAt: { + field: 'updated_at', + type: Sequelize.DATE + }, + deletedAt: { + field: 'deleted_at', + type: Sequelize.DATE + } + }, { + schema: config.DB_SCHEMA_NAME + }) + }, + down: async (queryInterface) => { + await queryInterface.dropTable({ + tableName: 'work_period_payments', + schema: config.DB_SCHEMA_NAME + }) + } +} diff --git a/migrations/2021-04-22-1-make-resource-booking-dates-store-no-timestamp.js b/migrations/2021-04-22-1-make-resource-booking-dates-store-no-timestamp.js new file mode 100644 index 00000000..52b4fc88 --- /dev/null +++ b/migrations/2021-04-22-1-make-resource-booking-dates-store-no-timestamp.js @@ -0,0 +1,42 @@ +const config = require('config') + +/* + * Make Resource Booking dates store no timestamps + * start_date: 2021-04-21T16:59:18.089Z -> 2021-04-21 + * end_date: 2021-05-21T16:59:18.089Z -> 2021-05-21 + * description: change type to DATE (DATEONLY) from TIMESTAMPTZ (DATE). + * By updating the column type, the existing data will be automatically cast to DATE. + */ + +module.exports = { + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'start_date', + { type: Sequelize.DATEONLY }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATEONLY }, + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + }, + down: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'start_date', + { type: Sequelize.DATE }, + { transaction }) + await queryInterface.changeColumn({ tableName: 'resource_bookings', schema: config.DB_SCHEMA_NAME }, 'end_date', + { type: Sequelize.DATE }, + { transaction }) + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + } +} diff --git a/migrations/2021-04-22-2-resource-booking-work-peirod-payment-add-billing-account-id-field.js b/migrations/2021-04-22-2-resource-booking-work-peirod-payment-add-billing-account-id-field.js new file mode 100644 index 00000000..4342ec33 --- /dev/null +++ b/migrations/2021-04-22-2-resource-booking-work-peirod-payment-add-billing-account-id-field.js @@ -0,0 +1,27 @@ +const config = require('config') + +/* + * Add billingAccountId field to the ResourceBooking and WorkPeriodPayment models. + */ + +module.exports = { + up: async (queryInterface, Sequelize) => { + const transaction = await queryInterface.sequelize.transaction() + try { + for (const tableName of ['resource_bookings', 'work_period_payments']) { + await queryInterface.addColumn({ tableName, schema: config.DB_SCHEMA_NAME }, 'billing_account_id', + { type: Sequelize.BIGINT }, + { transaction }) + } + await transaction.commit() + } catch (err) { + await transaction.rollback() + throw err + } + }, + down: async (queryInterface, Sequelize) => { + for (const tableName of ['resource_bookings', 'work_period_payments']) { + await queryInterface.removeColumn({ tableName, schema: config.DB_SCHEMA_NAME }, 'billing_account_id') + } + } +} diff --git a/migrations/2021-04-22-3-populate-work-periods-for-resource-bookings.js b/migrations/2021-04-22-3-populate-work-periods-for-resource-bookings.js new file mode 100644 index 00000000..0b20c9e6 --- /dev/null +++ b/migrations/2021-04-22-3-populate-work-periods-for-resource-bookings.js @@ -0,0 +1,81 @@ +const config = require('config') +const ResourceBooking = require('../src/models').ResourceBooking +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 + */ + +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(MAX_START_DATE) }, + end_date: { [Op.lt]: new Date(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.ensureUserById(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: null, + 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(MAX_START_DATE) }, + end_date: { [Op.lt]: new Date(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 97150812..50293037 100644 --- a/package-lock.json +++ b/package-lock.json @@ -418,7 +418,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@joi/date/-/date-2.0.1.tgz", "integrity": "sha512-vAnBxaPmyXRmHlbr5H3zY6x8ToW1a3c3gCo91dsf/HPKP2vS4sz2xzjyCE1up0vmFmSWgfDIyJMpRWVOG2cpZQ==", - "dev": true, "requires": { "moment": "2.x.x" } @@ -4890,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 23621ca5..fac8d7fc 100644 --- a/package.json +++ b/package.json @@ -15,23 +15,26 @@ "index:jobs": "node scripts/es/reIndexJobs.js", "index:job-candidates": "node scripts/es/reIndexJobCandidates.js", "index:resource-bookings": "node scripts/es/reIndexResourceBookings.js", + "index:work-periods": "node scripts/es/reIndexWorkPeriods.js", "data:export": "node scripts/data/exportData.js", "data:import": "node scripts/data/importData.js", "migrate": "npx sequelize db:migrate", "migrate:undo": "npx sequelize db:migrate:undo", - "test": "mocha test/unit/*.test.js --timeout 30000 --exit", + "test": "mocha test/unit/*.test.js --timeout 30000 --require test/prepare.js --exit", "services:up": "docker-compose -f ./local/docker-compose.yml up -d", "services:down": "docker-compose -f ./local/docker-compose.yml down", "services:logs": "docker-compose -f ./local/docker-compose.yml logs", "local:init": "npm run local:reset && npm run data:import -- --force", "local:reset": "npm run delete-index -- --force || true && npm run create-index -- --force && npm run init-db force", - "cov": "nyc --reporter=html --reporter=text mocha test/unit/*.test.js --timeout 30000 --exit" + "cov": "nyc --reporter=html --reporter=text npm run test", + "demo-payment": "node scripts/demo-payment" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@elastic/elasticsearch": "^7.9.1", + "@joi/date": "^2.0.1", "@topcoder-platform/topcoder-bus-api-wrapper": "github:topcoder-platform/tc-bus-api-wrapper", "aws-sdk": "^2.787.0", "bottleneck": "^2.19.5", @@ -59,7 +62,6 @@ "winston": "^3.3.3" }, "devDependencies": { - "@joi/date": "^2.0.1", "chai": "^4.2.0", "csv-parser": "^3.0.0", "mocha": "^8.1.3", diff --git a/scripts/common/helper.js b/scripts/common/helper.js new file mode 100644 index 00000000..fdda34c7 --- /dev/null +++ b/scripts/common/helper.js @@ -0,0 +1,84 @@ +/* + * Provide some commonly used functions for scripts. + */ +const csv = require('csv-parser') +const fs = require('fs') +const request = require('superagent') + +/** + * Load CSV data from file. + * + * @param {String} pathname the pathname for the file + * @param {Object} fieldNameMap mapping values of headers + * @returns {Array} the result jobs data + */ +async function loadCSVFromFile (pathname, fieldNameMap = {}) { + let lnum = 1 + const result = [] + return new Promise((resolve, reject) => { + fs.createReadStream(pathname) + .pipe(csv({ + mapHeaders: ({ header }) => fieldNameMap[header] || header + })) + .on('data', (data) => { + result.push({ ...data, _lnum: lnum }) + lnum += 1 + }) + .on('error', err => reject(err)) + .on('end', () => resolve(result)) + }) +} + +/** + * Get pathname from command line arguments. + * + * @returns {String} the pathname + */ +function getPathnameFromCommandline () { + if (process.argv.length < 3) { + throw new Error('pathname for the csv file is required') + } + const pathname = process.argv[2] + if (!fs.existsSync(pathname)) { + throw new Error(`pathname: ${pathname} path not exist`) + } + if (!fs.lstatSync(pathname).isFile()) { + throw new Error(`pathname: ${pathname} path is not a regular file`) + } + return pathname +} + +/** + * Sleep for a given number of milliseconds. + * + * @param {Number} milliseconds the sleep time + * @returns {undefined} + */ +async function sleep (milliseconds) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)) +} + +/** + * Find taas job by external id. + * + * @param {String} token the auth token + * @param {String} taasApiUrl url for TaaS API + * @param {String} externalId the external id + * @returns {Object} the result + */ +async function getJobByExternalId (token, taasApiUrl, externalId) { + const { body: jobs } = await request.get(`${taasApiUrl}/jobs`) + .query({ externalId }) + .set('Authorization', `Bearer ${token}`) + if (!jobs.length) { + throw new Error(`externalId: ${externalId} job not found`) + } + return jobs[0] +} + +module.exports = { + loadCSVFromFile, + getPathnameFromCommandline, + sleep, + getJobByExternalId +} diff --git a/scripts/common/logger.js b/scripts/common/logger.js new file mode 100644 index 00000000..273b3841 --- /dev/null +++ b/scripts/common/logger.js @@ -0,0 +1,10 @@ +/* + * Logger for scripts. + */ + +module.exports = { + info: (message) => console.log(`INFO: ${message}`), + debug: (message) => console.log(`DEBUG: ${message}`), + warn: (message) => console.log(`WARN: ${message}`), + error: (message) => console.log(`ERROR: ${message}`) +} diff --git a/scripts/data/exportData.js b/scripts/data/exportData.js index c443cb38..30529aa7 100644 --- a/scripts/data/exportData.js +++ b/scripts/data/exportData.js @@ -7,7 +7,7 @@ const helper = require('../../src/common/helper') const filePath = helper.getParamFromCliArgs() || config.DEFAULT_DATA_FILE_PATH const userPrompt = `WARNING: are you sure you want to export all data in the database to a json file with the path ${filePath}? This will overwrite the file.` -const dataModels = ['Job', 'JobCandidate', 'ResourceBooking'] +const dataModels = ['Job', 'JobCandidate', 'ResourceBooking', 'WorkPeriod', 'WorkPeriodPayment'] async function exportData () { await helper.promptUser(userPrompt, async () => { diff --git a/scripts/data/importData.js b/scripts/data/importData.js index 1f51e61c..e4daa58d 100644 --- a/scripts/data/importData.js +++ b/scripts/data/importData.js @@ -7,7 +7,7 @@ const helper = require('../../src/common/helper') const filePath = helper.getParamFromCliArgs() || config.DEFAULT_DATA_FILE_PATH const userPrompt = `WARNING: this would remove existing data. Are you sure you want to import data from a json file with the path ${filePath}?` -const dataModels = ['Job', 'JobCandidate', 'ResourceBooking'] +const dataModels = ['Job', 'JobCandidate', 'ResourceBooking', 'WorkPeriod', 'WorkPeriodPayment'] async function importData () { await helper.promptUser(userPrompt, async () => { diff --git a/scripts/demo-payment/README.md b/scripts/demo-payment/README.md new file mode 100644 index 00000000..d39e432b --- /dev/null +++ b/scripts/demo-payment/README.md @@ -0,0 +1,22 @@ +### DEMO PAYMENT SCRIPT + +This demo script tests the functionality of PaymentService. + +Parameters for creating payments are hardcoded in the script. There are severel groups of parameters, each of them tests a certain functionality of the demo service. You can always insert new group of parameters to run in the script. + +Before start set the following environment variables: +AUTH0_URL= +AUTH0_AUDIENCE= +AUTH0_AUDIENCE_UBAHN= +AUTH0_CLIENT_ID= +AUTH0_CLIENT_SECRET= + +To run the script use the following commands: + +``` +npm install +npm run lint +npm run demo-payment +``` + +Read the logger to see results. \ No newline at end of file diff --git a/scripts/demo-payment/index.js b/scripts/demo-payment/index.js new file mode 100644 index 00000000..f84880b9 --- /dev/null +++ b/scripts/demo-payment/index.js @@ -0,0 +1,114 @@ +require('../../src/bootstrap') +const logger = require('../../src/common/logger') +const paymentService = require('../../src/services/PaymentService') + +const options = [ + { + name: 'Test joi validation for projectId-1', + content: { + userHandle: 'pshah_manager', + amount: 3, + billingAccountId: 80000069, + name: 'test payment for pshah_manager', + description: '## test payment' + } + }, + { + name: 'Test joi validation for projectId-2', + content: { + projectId: 'project', + userHandle: 'pshah_manager', + amount: 3, + billingAccountId: 80000069, + name: 'test payment for pshah_manager', + description: '## test payment' + } + }, + { + name: 'Test joi validation for userHandle', + content: { + projectId: 17234, + amount: 3, + billingAccountId: 80000069, + name: 'test payment for pshah_manager', + description: '## test payment' + } + }, + { + name: 'Test joi validation for amount-1', + content: { + projectId: 17234, + userHandle: 'pshah_manager', + billingAccountId: 80000069, + name: 'test payment for pshah_manager', + description: '## test payment' + } + }, + { + name: 'Test joi validation for amount-2', + content: { + projectId: 17234, + userHandle: 'pshah_manager', + amount: -10, + billingAccountId: 80000069, + name: 'test payment for pshah_manager', + description: '## test payment' + } + }, + { + name: 'Successful payment creation', + content: { + projectId: 17234, + userHandle: 'pshah_manager', + amount: 3, + billingAccountId: 80000069, + name: 'test payment for pshah_manager', + description: '## test payment' + } + }, + { + name: 'Successful payment creation without name and description', + content: { + projectId: 17234, + userHandle: 'pshah_customer', + amount: 2, + billingAccountId: 80000069 + } + }, + { + name: 'Failing payment creation with no active billing account', + content: { + projectId: 16839, + userHandle: 'pshah_customer', + amount: 2, + billingAccountId: 80000069, + name: 'test payment for pshah_customer', + description: '## test payment' + } + }, + { + name: 'Failing payment creation with non existing user', + content: { + projectId: 17234, + userHandle: 'eisbilir', + amount: 2, + billingAccountId: 80000069 + } + } +] + +const test = async () => { + for (const option of options) { + logger.info({ component: 'demo-payment', context: 'test', message: `Starting to create payment for: ${option.name}` }) + await paymentService.createPayment(option.content) + .then(data => { + logger.info({ component: 'demo-payment', context: 'test', message: `Payment successfuly created for: ${option.name}` }) + }) + // eslint-disable-next-line handle-callback-err + .catch(err => { + logger.error({ component: 'demo-payment', context: 'test', message: `Payment can't be created for: ${option.name}` }) + }) + } +} +// wait for bootstrap to complete it's job. +setTimeout(test, 2000) diff --git a/scripts/es/createIndex.js b/scripts/es/createIndex.js index d2c72943..4591214a 100644 --- a/scripts/es/createIndex.js +++ b/scripts/es/createIndex.js @@ -8,7 +8,8 @@ const helper = require('../../src/common/helper') const indices = [ config.get('esConfig.ES_INDEX_JOB'), config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), - config.get('esConfig.ES_INDEX_RESOURCE_BOOKING') + config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'), + config.get('esConfig.ES_INDEX_WORK_PERIOD') ] const userPrompt = `WARNING: Are you sure want to create the following elasticsearch indices: ${indices}?` diff --git a/scripts/es/deleteIndex.js b/scripts/es/deleteIndex.js index 6e30995a..8acffe33 100644 --- a/scripts/es/deleteIndex.js +++ b/scripts/es/deleteIndex.js @@ -8,7 +8,8 @@ const helper = require('../../src/common/helper') const indices = [ config.get('esConfig.ES_INDEX_JOB'), config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), - config.get('esConfig.ES_INDEX_RESOURCE_BOOKING') + config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'), + config.get('esConfig.ES_INDEX_WORK_PERIOD') ] const userPrompt = `WARNING: this would remove existent data! Are you sure want to delete the following eleasticsearch indices: ${indices}?` diff --git a/scripts/es/reIndexAll.js b/scripts/es/reIndexAll.js index 65ddc2ec..215efaa2 100644 --- a/scripts/es/reIndexAll.js +++ b/scripts/es/reIndexAll.js @@ -13,6 +13,7 @@ async function indexAll () { await helper.indexBulkDataToES('Job', config.get('esConfig.ES_INDEX_JOB'), logger) await helper.indexBulkDataToES('JobCandidate', config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), logger) await helper.indexBulkDataToES('ResourceBooking', config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'), logger) + await helper.indexBulkDataToES('WorkPeriod', config.get('esConfig.ES_INDEX_WORK_PERIOD'), logger) process.exit(0) } catch (err) { logger.logFullError(err, { component: 'indexAll' }) diff --git a/scripts/es/reIndexWorkPeriods.js b/scripts/es/reIndexWorkPeriods.js new file mode 100644 index 00000000..a759d6c1 --- /dev/null +++ b/scripts/es/reIndexWorkPeriods.js @@ -0,0 +1,37 @@ +/** + * Reindex WorkPeriods data in Elasticsearch using data from database + */ +const config = require('config') +const logger = require('../../src/common/logger') +const helper = require('../../src/common/helper') + +const workPeriodId = helper.getParamFromCliArgs() +const index = config.get('esConfig.ES_INDEX_WORK_PERIOD') +const reIndexAllWorkPeriodsPrompt = `WARNING: this would remove existent data! Are you sure you want to reindex the index ${index}` +const reIndexWorkPeriodPrompt = `WARNING: this would remove existent data! Are you sure you want to reindex the document with id ${workPeriodId} in index ${index}?` + +async function reIndexWorkPeriods () { + if (workPeriodId === null) { + await helper.promptUser(reIndexAllWorkPeriodsPrompt, async () => { + try { + await helper.indexBulkDataToES('WorkPeriod', index, logger) + process.exit(0) + } catch (err) { + logger.logFullError(err, { component: 'reIndexWorkPeriods' }) + process.exit(1) + } + }) + } else { + await helper.promptUser(reIndexWorkPeriodPrompt, async () => { + try { + await helper.indexDataToEsById(workPeriodId, 'WorkPeriod', index, logger) + process.exit(0) + } catch (err) { + logger.logFullError(err, { component: 'reIndexWorkPeriods' }) + process.exit(1) + } + }) + } +} + +reIndexWorkPeriods() diff --git a/scripts/recruit-crm-job-import/config.js b/scripts/recruit-crm-job-import/config.js index 58a96031..8ee6cf42 100644 --- a/scripts/recruit-crm-job-import/config.js +++ b/scripts/recruit-crm-job-import/config.js @@ -5,7 +5,7 @@ const config = require('config') -const namespace = process.env.RCRM_IMPORT_CONFIG_NAMESAPCE || 'RCRM_IMPORT_' +const namespace = process.env.RCRM_IMPORT_CONFIG_NAMESAPCE || '' module.exports = { SLEEP_TIME: process.env[`${namespace}SLEEP_TIME`] || 500, diff --git a/scripts/recruit-crm-job-import/helper.js b/scripts/recruit-crm-job-import/helper.js index 5cdf10ff..43591ff3 100644 --- a/scripts/recruit-crm-job-import/helper.js +++ b/scripts/recruit-crm-job-import/helper.js @@ -2,18 +2,27 @@ * Provide some commonly used functions for the RCRM import script. */ const config = require('./config') +const _ = require('lodash') const request = require('superagent') -const { getM2MToken } = require('../../src/common/helper') +const commonHelper = require('../common/helper') -/** - * Sleep for a given number of milliseconds. - * - * @param {Number} milliseconds the sleep time - * @returns {undefined} +/* + * Function to get M2M token + * @returns {Promise} */ -async function sleep (milliseconds) { - return new Promise((resolve) => setTimeout(resolve, milliseconds)) -} +const getM2MToken = (() => { + const m2mAuth = require('tc-core-library-js').auth.m2m + const m2m = m2mAuth(_.pick(config, [ + 'AUTH0_URL', + 'AUTH0_AUDIENCE', + 'AUTH0_CLIENT_ID', + 'AUTH0_CLIENT_SECRET', + 'AUTH0_PROXY_SERVER_URL' + ])) + return async () => { + return await m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET) + } +})() /** * Create a new job via taas api. @@ -38,13 +47,7 @@ async function createJob (data) { */ async function getJobByExternalId (externalId) { const token = await getM2MToken() - const { body: jobs } = await request.get(`${config.TAAS_API_URL}/jobs`) - .query({ externalId }) - .set('Authorization', `Bearer ${token}`) - if (!jobs.length) { - throw new Error(`externalId: ${externalId} job not found`) - } - return jobs[0] + return commonHelper.getJobByExternalId(token, config.TAAS_API_URL, externalId) } /** @@ -131,7 +134,9 @@ async function getProjectByDirectProjectId (directProjectId) { } module.exports = { - sleep, + sleep: commonHelper.sleep, + loadCSVFromFile: commonHelper.loadCSVFromFile, + getPathnameFromCommandline: commonHelper.getPathnameFromCommandline, createJob, getJobByExternalId, updateResourceBookingStatus, diff --git a/scripts/recruit-crm-job-import/index.js b/scripts/recruit-crm-job-import/index.js index 427a64f6..c82254ab 100644 --- a/scripts/recruit-crm-job-import/index.js +++ b/scripts/recruit-crm-job-import/index.js @@ -2,8 +2,6 @@ * Script to import Jobs data from Recruit CRM to Taas API. */ -const csv = require('csv-parser') -const fs = require('fs') const Joi = require('joi') .extend(require('@joi/date')) const _ = require('lodash') @@ -38,48 +36,6 @@ function validateJob (job) { return jobSchema.validate(job) } -/** - * Load Recruit CRM jobs data from file. - * - * @param {String} pathname the pathname for the file - * @returns {Array} the result jobs data - */ -async function loadRcrmJobsFromFile (pathname) { - let lnum = 1 - const result = [] - return new Promise((resolve, reject) => { - fs.createReadStream(pathname) - .pipe(csv({ - mapHeaders: ({ header }) => constants.fieldNameMap[header] || header - })) - .on('data', (data) => { - result.push({ ...data, _lnum: lnum }) - lnum += 1 - }) - .on('error', err => reject(err)) - .on('end', () => resolve(result)) - }) -} - -/** - * Get pathname for a csv file from command line arguments. - * - * @returns {undefined} - */ -function getPathname () { - if (process.argv.length < 3) { - throw new Error('pathname for the csv file is required') - } - const pathname = process.argv[2] - if (!fs.existsSync(pathname)) { - throw new Error(`pathname: ${pathname} path not exist`) - } - if (!fs.lstatSync(pathname).isFile()) { - throw new Error(`pathname: ${pathname} path is not a regular file`) - } - return pathname -} - /** * Process single job data. The processing consists of: * - Validate the data. @@ -146,8 +102,8 @@ async function processJob (job, info = []) { * @returns {undefined} */ async function main () { - const pathname = getPathname() - const jobs = await loadRcrmJobsFromFile(pathname) + const pathname = helper.getPathnameFromCommandline() + const jobs = await helper.loadCSVFromFile(pathname, constants.fieldNameMap) const report = new Report() for (const job of jobs) { logger.debug(`processing line #${job._lnum} - ${JSON.stringify(job)}`) diff --git a/scripts/recruit-crm-job-import/logger.js b/scripts/recruit-crm-job-import/logger.js index ccb00102..dc38cab5 100644 --- a/scripts/recruit-crm-job-import/logger.js +++ b/scripts/recruit-crm-job-import/logger.js @@ -1,10 +1,6 @@ /* * Logger for the RCRM import script. */ +const logger = require('../common/logger') -module.exports = { - info: (message) => console.log(`INFO: ${message}`), - debug: (message) => console.log(`DEBUG: ${message}`), - warn: (message) => console.log(`WARN: ${message}`), - error: (message) => console.log(`ERROR: ${message}`) -} +module.exports = logger diff --git a/scripts/recruit-crm-job-sync/README.md b/scripts/recruit-crm-job-sync/README.md new file mode 100644 index 00000000..38d85877 --- /dev/null +++ b/scripts/recruit-crm-job-sync/README.md @@ -0,0 +1,80 @@ +Recruit CRM Job Data Sync Script +=== + +# Configuration +Configuration file is at `./scripts/recruit-crm-job-sync/config.js`. + + +# Usage +``` bash +node scripts/recruit-crm-job-sync +``` + +By default the script updates jobs via `TC_API`. + +# Example + +1. Follow the README for `taas-apis` to deploy Taas API locally +2. Create two jobs via `Jobs > create job with booking manager` in Postman, with external ids `51913016` and `51892637` for each of the jobs. + + **NOTE**: The external ids `51913016` and `51902826` could be found at `scripts/recruit-crm-job-sync/example_data.csv` under the Slug column. + +3. Configure env variable `RCRM_SYNC_TAAS_API_URL` so that the script could make use of the local API: + + ``` bash + export RCRM_SYNC_TAAS_API_URL=http://localhost:3000/api/v5 + ``` + +4. Run the script against the sample CSV file and pipe the output from the script to a temporary file: + + ``` bash + node scripts/recruit-crm-job-sync scripts/recruit-crm-job-sync/example_data.csv | tee /tmp/report.txt + ``` + + The output should be like this: + + ``` bash + DEBUG: processing line #1 - {"ID":"1","Name":"Data job Engineer","Description":"","Qualification":"","Specialization":"","Minimum Experience In Years":"1","Maximum Experience In Years":"3","Minimum Annual Salary":"10","Maximum Annual Salary":"20","Number Of Openings":"2","Job Status":"Closed","Company":"company 1","Contact":" ","Currency":"$","allowApply":"Yes","Collaborator":"","Locality":"","City":"","Job Code":"J123456","Createdby":"abc","Created On":"02-Jun-20","Updated By":"abc","Updated On":"17-Feb-21","Owner":"abc","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"51892637","_lnum":1} + ERROR: #1 - [EXTERNAL_ID_NOT_FOUND] externalId: 51892637 job not found + DEBUG: processed line #1 + DEBUG: processing line #2 - {"ID":"2","Name":"JAVA coffee engineer","Description":"","Qualification":"","Specialization":"","Minimum Experience In Years":"2","Maximum Experience In Years":"5","Minimum Annual Salary":"10","Maximum Annual Salary":"20","Number Of Openings":"10","Job Status":"Closed","Company":"company 2","Contact":"abc","Currency":"$","allowApply":"Yes","Collaborator":"","Locality":"","City":"","Job Code":"J123457","Createdby":"abc","Created On":"02-Jun-20","Updated By":"abc","Updated On":"12-Nov-20","Owner":"abc","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"51913016","_lnum":2} + DEBUG: jobId: 34cee9aa-e45f-47ed-9555-ffd3f7196fec isApplicationPageActive(current): false - isApplicationPageActive(to be synced): true + INFO: #2 - id: 34cee9aa-e45f-47ed-9555-ffd3f7196fec isApplicationPageActive: true "job" updated + DEBUG: processed line #2 + DEBUG: processing line #3 - {"ID":"3","Name":"QA Seleinium","Description":"","Qualification":"","Specialization":"","Minimum Experience In Years":"3","Maximum Experience In Years":"7","Minimum Annual Salary":"10","Maximum Annual Salary":"20","Number Of Openings":"4","Job Status":"Canceled","Company":"company 3","Contact":" ","Currency":"$","allowApply":"No","Collaborator":"","Locality":"","City":"","Job Code":"J123458","Createdby":"abc","Created On":"04-Jun-20","Updated By":"abc","Updated On":"12-Nov-20","Owner":"abc","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"51902826","_lnum":3} + DEBUG: jobId: 4acde317-c364-4b79-aa77-295b98143c8b isApplicationPageActive(current): false - isApplicationPageActive(to be synced): false + WARN: #3 - isApplicationPageActive is already set + DEBUG: processed line #3 + DEBUG: processing line #4 - {"ID":"5","Name":"Data Engineers and Data Architects","Description":"","Qualification":"","Specialization":"","Minimum Experience In Years":"4","Maximum Experience In Years":"9","Minimum Annual Salary":"10","Maximum Annual Salary":"20","Number Of Openings":"8","Job Status":"Closed","Company":"company 4","Contact":" ","Currency":"$","allowApply":"Yes","Collaborator":"","Locality":"","City":"","Job Code":"J123459","Createdby":"abc","Created On":"09-Jun-20","Updated By":"abc","Updated On":"12-Nov-20","Owner":"abc","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"51811161","_lnum":4} + ERROR: #4 - [EXTERNAL_ID_NOT_FOUND] externalId: 51811161 job not found + DEBUG: processed line #4 + DEBUG: processing line #5 - {"ID":"6","Name":"Docker Engineer","Description":"Java & J2EE or Python, Docker, Kubernetes, AWS or GCP","Qualification":"","Specialization":"","Minimum Experience In Years":"5","Maximum Experience In Years":"10","Minimum Annual Salary":"10","Maximum Annual Salary":"20","Number Of Openings":"5","Job Status":"Closed","Company":"company 5","Contact":" ","Currency":"$","allowApply":"No","Collaborator":"","Locality":"","City":"","Job Code":"J123460","Createdby":"abc","Created On":"12-Jun-20","Updated By":"abc","Updated On":"12-Nov-20","Owner":"abc","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"51821342","_lnum":5} + ERROR: #5 - [EXTERNAL_ID_NOT_FOUND] externalId: 51821342 job not found + DEBUG: processed line #5 + DEBUG: processing line #6 - {"ID":"7","Name":"lambda Developers","Description":"","Qualification":"","Specialization":"","Minimum Experience In Years":"0","Maximum Experience In Years":"0","Minimum Annual Salary":"10","Maximum Annual Salary":"20","Number Of Openings":"2","Job Status":"Closed","Company":"company 6","Contact":"abc","Currency":"$","allowApply":"Yes","Collaborator":"","Locality":"","City":"","Job Code":"J123461","Createdby":"abc","Created On":"12-Jun-20","Updated By":"abc","Updated On":"12-Nov-20","Owner":"abc","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"51831524","_lnum":6} + ERROR: #6 - [EXTERNAL_ID_NOT_FOUND] externalId: 51831524 job not found + DEBUG: processed line #6 + DEBUG: processing line #7 - {"ID":"","Name":"","Description":"","Qualification":"","Specialization":"","Minimum Experience In Years":"","Maximum Experience In Years":"","Minimum Annual Salary":"","Maximum Annual Salary":"","Number Of Openings":"","Job Status":"","Company":"","Contact":"","Currency":"","allowApply":"","Collaborator":"","Locality":"","City":"","Job Code":"","Createdby":"","Created On":"","Updated By":"","Updated On":"","Owner":"","Custom Column 1":"","Custom Column 2":"","Custom Column 3":"","Custom Column 4":"","Custom Column 5":"","Custom Column 6":"","Custom Column 7":"","Custom Column 8":"","Custom Column 9":"","Custom Column 10":"","Custom Column 11":"","Custom Column 12":"","Custom Column 13":"","Custom Column 14":"","Custom Column 15":"","externalId":"","_lnum":7} + ERROR: #7 - "allowApply" must be one of [Yes, No] + DEBUG: processed line #7 + INFO: === summary === + INFO: No. of records read = 7 + INFO: No. of records updated for field isApplicationPageActive = true = 1 + INFO: No. of records updated for field isApplicationPageActive = false = 0 + INFO: No. of records : externalId not found = 4 + INFO: No. of records failed(all) = 5 + INFO: No. of records failed(excluding "externalId not found") = 1 + INFO: No. of records skipped = 1 + INFO: done! + ``` + + The following command could be used to extract the summary from the output: + + ``` bash + cat /tmp/report.txt | grep 'No. of records' | cut -d' ' -f2- + ``` + + To list all skipped lines: + + ``` bash + cat /tmp/report.txt | grep 'WARN' -B 3 diff --git a/scripts/recruit-crm-job-sync/config.js b/scripts/recruit-crm-job-sync/config.js new file mode 100644 index 00000000..e6eece80 --- /dev/null +++ b/scripts/recruit-crm-job-sync/config.js @@ -0,0 +1,20 @@ +/* + * Configuration for the RCRM sync script. + * Namespace is created to allow to configure the env variables for this script independently. + */ + +const config = require('config') + +const namespace = process.env.RCRM_SYNC_CONFIG_NAMESAPCE || '' + +module.exports = { + SLEEP_TIME: process.env[`${namespace}SLEEP_TIME`] || 500, + TAAS_API_URL: process.env[`${namespace}TAAS_API_URL`] || config.TC_API, + + AUTH0_URL: process.env[`${namespace}AUTH0_URL`] || config.AUTH0_URL, + AUTH0_AUDIENCE: process.env[`${namespace}AUTH0_AUDIENCE`] || config.AUTH0_AUDIENCE, + TOKEN_CACHE_TIME: process.env[`${namespace}TOKEN_CACHE_TIME`] || config.TOKEN_CACHE_TIME, + AUTH0_CLIENT_ID: process.env[`${namespace}AUTH0_CLIENT_ID`] || config.AUTH0_CLIENT_ID, + AUTH0_CLIENT_SECRET: process.env[`${namespace}AUTH0_CLIENT_SECRET`] || config.AUTH0_CLIENT_SECRET, + AUTH0_PROXY_SERVER_URL: process.env[`${namespace}AUTH0_PROXY_SERVER_URL`] || config.AUTH0_PROXY_SERVER_URL +} diff --git a/scripts/recruit-crm-job-sync/constants.js b/scripts/recruit-crm-job-sync/constants.js new file mode 100644 index 00000000..2d06ef96 --- /dev/null +++ b/scripts/recruit-crm-job-sync/constants.js @@ -0,0 +1,15 @@ +/* + * Constants for the RCRM sync script. + */ + +module.exports = { + ProcessingStatus: { + Successful: 'successful', + Failed: 'failed', + Skipped: 'skipped' + }, + fieldNameMap: { + 'Allow Apply': 'allowApply', + Slug: 'externalId' + } +} diff --git a/scripts/recruit-crm-job-sync/example_data.csv b/scripts/recruit-crm-job-sync/example_data.csv new file mode 100644 index 00000000..44ce1c88 --- /dev/null +++ b/scripts/recruit-crm-job-sync/example_data.csv @@ -0,0 +1,8 @@ +ID,Name,Description,Qualification,Specialization,Minimum Experience In Years,Maximum Experience In Years,Minimum Annual Salary,Maximum Annual Salary,Number Of Openings,Job Status,Company,Contact,Currency,Allow Apply,Collaborator,Locality,City,Job Code,Createdby,Created On,Updated By,Updated On,Owner,Custom Column 1,Custom Column 2,Custom Column 3,Custom Column 4,Custom Column 5,Custom Column 6,Custom Column 7,Custom Column 8,Custom Column 9,Custom Column 10,Custom Column 11,Custom Column 12,Custom Column 13,Custom Column 14,Custom Column 15,Slug +1,Data job Engineer,,,,1,3,10,20,2,Closed,company 1, ,$,Yes,,,,J123456,abc,02-Jun-20,abc,17-Feb-21,abc,,,,,,,,,,,,,,,,51892637 +2,JAVA coffee engineer,,,,2,5,10,20,10,Closed,company 2,abc,$,Yes,,,,J123457,abc,02-Jun-20,abc,12-Nov-20,abc,,,,,,,,,,,,,,,,51913016 +3,QA Seleinium,,,,3,7,10,20,4,Canceled,company 3, ,$,No,,,,J123458,abc,04-Jun-20,abc,12-Nov-20,abc,,,,,,,,,,,,,,,,51902826 +5,Data Engineers and Data Architects,,,,4,9,10,20,8,Closed,company 4, ,$,Yes,,,,J123459,abc,09-Jun-20,abc,12-Nov-20,abc,,,,,,,,,,,,,,,,51811161 +6,Docker Engineer,"Java & J2EE or Python, Docker, Kubernetes, AWS or GCP",,,5,10,10,20,5,Closed,company 5, ,$,No,,,,J123460,abc,12-Jun-20,abc,12-Nov-20,abc,,,,,,,,,,,,,,,,51821342 +7,lambda Developers,,,,0,0,10,20,2,Closed,company 6,abc,$,Yes,,,,J123461,abc,12-Jun-20,abc,12-Nov-20,abc,,,,,,,,,,,,,,,,51831524 +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, \ No newline at end of file diff --git a/scripts/recruit-crm-job-sync/helper.js b/scripts/recruit-crm-job-sync/helper.js new file mode 100644 index 00000000..e28efb17 --- /dev/null +++ b/scripts/recruit-crm-job-sync/helper.js @@ -0,0 +1,60 @@ +/* + * Provide some commonly used functions for the RCRM sync script. + */ +const config = require('./config') +const _ = require('lodash') +const commonHelper = require('../common/helper') +const request = require('superagent') + +/* + * Function to get M2M token + * @returns {Promise} + */ +const getM2MToken = (() => { + const m2mAuth = require('tc-core-library-js').auth.m2m + const m2m = m2mAuth(_.pick(config, [ + 'AUTH0_URL', + 'AUTH0_AUDIENCE', + 'AUTH0_CLIENT_ID', + 'AUTH0_CLIENT_SECRET', + 'AUTH0_PROXY_SERVER_URL' + ])) + return async () => { + return await m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET) + } +})() + +/** + * Find taas job by external id. + * + * @param {String} externalId the external id + * @returns {Object} the result + */ +async function getJobByExternalId (externalId) { + const token = await getM2MToken() + return commonHelper.getJobByExternalId(token, config.TAAS_API_URL, externalId) +} + +/** + * Partially update a job. + * + * @param {String} jobId the job id + * @param {Object} data the data to be updated + * @returns {Object} the result job + */ +async function updateJob (jobId, data) { + const token = await getM2MToken() + const { body: job } = await request.patch(`${config.TAAS_API_URL}/jobs/${jobId}`) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .send(data) + return job +} + +module.exports = { + sleep: commonHelper.sleep, + loadCSVFromFile: commonHelper.loadCSVFromFile, + getPathnameFromCommandline: commonHelper.getPathnameFromCommandline, + getJobByExternalId, + updateJob +} diff --git a/scripts/recruit-crm-job-sync/index.js b/scripts/recruit-crm-job-sync/index.js new file mode 100644 index 00000000..f10cd2e9 --- /dev/null +++ b/scripts/recruit-crm-job-sync/index.js @@ -0,0 +1,96 @@ +/* + * Script to sync values of Jobs from Recruit CRM to Taas API. + */ + +const Joi = require('joi') +const Report = require('./report') +const config = require('./config') +const helper = require('./helper') +const constants = require('./constants') +const logger = require('./logger') + +const jobSchema = Joi.object({ + allowApply: Joi.string().valid('Yes', 'No').required(), + externalId: Joi.string().allow('') +}).unknown(true) + +/** + * Process single job data. The processing consists of: + * - Validate the data. + * - Skip processing if externalId is missing. + * - Search job by externalId and update its `isApplicationPageActive` property + (skip processing if `isApplicationPageActive` is already set). + * + * @param {Object} job the job data + * @param {Array} info contains processing details + * @returns {Object} + */ +async function processJob (job, info = []) { + // validate the data + const { value: data, error } = jobSchema.validate(job) + data.isApplicationPageActive = data.allowApply === 'Yes' + if (error) { + info.push({ text: error.details[0].message, tag: 'validation_error' }) + return { status: constants.ProcessingStatus.Failed, info } + } + // skip processing if externalId is missing + if (!data.externalId) { + info.push({ text: 'externalId is missing', tag: 'external_id_missing' }) + return { status: constants.ProcessingStatus.Skipped, info } + } + try { + // search job by externalId and update its `isApplicationPageActive` property + const existingJob = await helper.getJobByExternalId(data.externalId) + logger.debug(`jobId: ${existingJob.id} isApplicationPageActive(current): ${existingJob.isApplicationPageActive} - isApplicationPageActive(to be synced): ${data.isApplicationPageActive}`) + // skip processing if `isApplicationPageActive` is already set + if (existingJob.isApplicationPageActive === data.isApplicationPageActive) { + info.push({ text: 'isApplicationPageActive is already set', tag: 'is_application_page_active_already_set' }) + return { status: constants.ProcessingStatus.Skipped, info } + } + const updatedJob = await helper.updateJob(existingJob.id, { isApplicationPageActive: data.allowApply === 'Yes' }) + info.push({ text: `id: ${existingJob.id} isApplicationPageActive: ${updatedJob.isApplicationPageActive} "job" updated`, tag: 'job_is_application_page_active_updated', currentValue: updatedJob.isApplicationPageActive }) + return { status: constants.ProcessingStatus.Successful, info } + } catch (err) { + if (!(err.message && err.message.includes('job not found'))) { + throw err + } + info.push({ text: `[EXTERNAL_ID_NOT_FOUND] ${err.message}`, tag: 'external_id_not_found' }) + return { status: constants.ProcessingStatus.Failed, info } + } +} + +/** + * The entry of the script. + * + * @returns {undefined} + */ +async function main () { + const pathname = helper.getPathnameFromCommandline() + const jobs = await helper.loadCSVFromFile(pathname, constants.fieldNameMap) + const report = new Report() + for (const job of jobs) { + logger.debug(`processing line #${job._lnum} - ${JSON.stringify(job)}`) + try { + const result = await processJob(job) + report.add({ lnum: job._lnum, ...result }) + } catch (err) { + if (err.response) { + report.add({ lnum: job._lnum, status: constants.ProcessingStatus.Failed, info: [{ text: err.response.error.toString().split('\n')[0], tag: 'request_error' }] }) + } else { + report.add({ lnum: job._lnum, status: constants.ProcessingStatus.Failed, info: [{ text: err.message, tag: 'internal_error' }] }) + } + } + report.print() + logger.debug(`processed line #${job._lnum}`) + await helper.sleep(config.SLEEP_TIME) + } + report.printSummary() +} + +main().then(() => { + logger.info('done!') + process.exit() +}).catch(err => { + logger.error(err.message) + process.exit(1) +}) diff --git a/scripts/recruit-crm-job-sync/logger.js b/scripts/recruit-crm-job-sync/logger.js new file mode 100644 index 00000000..5c6afcd8 --- /dev/null +++ b/scripts/recruit-crm-job-sync/logger.js @@ -0,0 +1,6 @@ +/* + * Logger for the RCRM sync script. + */ +const logger = require('../common/logger') + +module.exports = logger diff --git a/scripts/recruit-crm-job-sync/report.js b/scripts/recruit-crm-job-sync/report.js new file mode 100644 index 00000000..c24a7a75 --- /dev/null +++ b/scripts/recruit-crm-job-sync/report.js @@ -0,0 +1,59 @@ +/* + * The Report class. + */ + +const logger = require('./logger') +const constants = require('./constants') +const _ = require('lodash') + +class Report { + constructor () { + this.messages = [] + } + + // append a message to the report + add (message) { + this.messages.push(message) + } + + // print the last message to the console + print () { + const lastMessage = this.messages[this.messages.length - 1] + const output = `#${lastMessage.lnum} - ${_.map(lastMessage.info, 'text').join('; ')}` + if (lastMessage.status === constants.ProcessingStatus.Skipped) { + logger.warn(output) + } + if (lastMessage.status === constants.ProcessingStatus.Successful) { + logger.info(output) + } + if (lastMessage.status === constants.ProcessingStatus.Failed) { + logger.error(output) + } + } + + // print a summary to the console + printSummary () { + const groups = _.groupBy(this.messages, 'status') + const groupsByTag = _.groupBy(_.flatten(_.map(this.messages, message => message.info)), 'tag') + // summarize total fails + const failure = groups[constants.ProcessingStatus.Failed] || [] + // summarize total skips + const skips = groups[constants.ProcessingStatus.Skipped] || [] + // summarize total jobs with isApplicationPageActive being set to true/false + const groupsByisApplicationPageActive = _.groupBy(groupsByTag.job_is_application_page_active_updated, 'currentValue') + const jobsWithIsApplicationPageActiveSetToTrue = groupsByisApplicationPageActive.true || [] + const jobsWithIsApplicationPageActiveSetToFalse = groupsByisApplicationPageActive.false || [] + // summarize total records with externalId not found in Taas API + const recordsWithExternalIdNotFound = groupsByTag.external_id_not_found || [] + logger.info('=== summary ===') + logger.info(`No. of records read = ${this.messages.length}`) + logger.info(`No. of records updated for field isApplicationPageActive = true = ${jobsWithIsApplicationPageActiveSetToTrue.length}`) + logger.info(`No. of records updated for field isApplicationPageActive = false = ${jobsWithIsApplicationPageActiveSetToFalse.length}`) + logger.info(`No. of records : externalId not found = ${recordsWithExternalIdNotFound.length}`) + logger.info(`No. of records failed(all) = ${failure.length}`) + logger.info(`No. of records failed(excluding "externalId not found") = ${failure.length - recordsWithExternalIdNotFound.length}`) + logger.info(`No. of records skipped = ${skips.length}`) + } +} + +module.exports = Report diff --git a/src/bootstrap.js b/src/bootstrap.js index a799ae18..bc5b0b47 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -2,14 +2,19 @@ const fs = require('fs') const Joi = require('joi') const path = require('path') const logger = require('./common/logger') +const constants = require('../app-constants') +const config = require('config') 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', 'topcoder-rejected') Joi.title = () => Joi.string().max(128) +Joi.paymentStatus = () => Joi.string().valid('pending', 'partially-completed', 'completed', 'cancelled') +Joi.workPeriodPaymentStatus = () => Joi.string().valid('completed', 'cancelled') // Empty string is not allowed by Joi by default and must be enabled with allow(''). // See https://joi.dev/api/?v=17.3.0#string fro details why it's like this. // In many cases we would like to allow empty string to make it easier to create UI for editing data. @@ -33,3 +38,14 @@ function buildServices (dir) { } buildServices(path.join(__dirname, 'services')) + +// validate some configurable parameters for the app +const paymentProcessingSwitchSchema = Joi.string().label('PAYMENT_PROCESSING_SWITCH').valid( + ...Object.values(constants.PaymentProcessingSwitch) +) +try { + Joi.attempt(config.PAYMENT_PROCESSING_SWITCH, paymentProcessingSwitchSchema) +} catch (err) { + console.error(err.message) + process.exit(1) +} diff --git a/src/common/errors.js b/src/common/errors.js index 92b4e69b..2e7444d5 100644 --- a/src/common/errors.js +++ b/src/common/errors.js @@ -35,5 +35,6 @@ module.exports = { UnauthorizedError: createError('UnauthorizedError', 401), ForbiddenError: createError('ForbiddenError', 403), NotFoundError: createError('NotFoundError', 404), + ConflictError: createError('ConflictError', 409), InternalServerError: createError('InternalServerError', 500) } diff --git a/src/common/helper.js b/src/common/helper.js index 50adc94b..c081467c 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') const localLogger = { debug: (message) => logger.debug({ component: 'helper', context: message.context, message: message.message }), @@ -92,11 +93,43 @@ esIndexPropertyMapping[config.get('esConfig.ES_INDEX_RESOURCE_BOOKING')] = { userId: { type: 'keyword' }, jobId: { type: 'keyword' }, status: { type: 'keyword' }, - startDate: { type: 'date' }, - endDate: { type: 'date' }, + startDate: { type: 'date', format: 'yyyy-MM-dd' }, + endDate: { type: 'date', format: 'yyyy-MM-dd' }, memberRate: { type: 'float' }, customerRate: { type: 'float' }, rateType: { type: 'keyword' }, + billingAccountId: { type: 'integer' }, + createdAt: { type: 'date' }, + createdBy: { type: 'keyword' }, + updatedAt: { type: 'date' }, + updatedBy: { type: 'keyword' } +} +esIndexPropertyMapping[config.get('esConfig.ES_INDEX_WORK_PERIOD')] = { + resourceBookingId: { type: 'keyword' }, + userHandle: { type: 'keyword' }, + projectId: { type: 'integer' }, + userId: { type: 'keyword' }, + startDate: { type: 'date', format: 'yyyy-MM-dd' }, + endDate: { type: 'date', format: 'yyyy-MM-dd' }, + daysWorked: { type: 'integer' }, + memberRate: { type: 'float' }, + customerRate: { type: 'float' }, + paymentStatus: { type: 'keyword' }, + payments: { + type: 'nested', + properties: { + id: { type: 'keyword' }, + workPeriodId: { type: 'keyword' }, + challengeId: { type: 'keyword' }, + amount: { type: 'float' }, + status: { type: 'keyword' }, + billingAccountId: { type: 'integer' }, + createdAt: { type: 'date' }, + createdBy: { type: 'keyword' }, + updatedAt: { type: 'date' }, + updatedBy: { type: 'keyword' } + } + }, createdAt: { type: 'date' }, createdBy: { type: 'keyword' }, updatedAt: { type: 'date' }, @@ -234,9 +267,18 @@ async function indexBulkDataToES (modelName, indexName, logger) { // get data from db logger.info({ component: 'indexBulkDataToES', message: 'Getting data from database' }) const model = models[modelName] - const data = await model.findAll({ + const criteria = { raw: true - }) + } + if (modelName === 'WorkPeriod') { + criteria.raw = false + criteria.include = [{ + model: models.WorkPeriodPayment, + as: 'payments', + required: false + }] + } + const data = await model.findAll(criteria) if (_.isEmpty(data)) { logger.info({ component: 'indexBulkDataToES', message: `No data in database for ${modelName}` }) return @@ -277,7 +319,7 @@ async function indexDataToEsById (id, modelName, indexName, logger) { logger.info({ component: 'indexDataToEsById', message: 'Getting data from database' }) const model = models[modelName] - const data = await model.findById(id) + const data = await model.findById(id, modelName === 'WorkPeriod') logger.info({ component: 'indexDataToEsById', message: 'Indexing data into Elasticsearch' }) await esClient.index({ index: indexName, @@ -355,6 +397,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) } /** @@ -598,17 +641,17 @@ function encodeQueryString (queryObj, nesting = '') { } /** - * Function to get user ids - * @param {Integer} userId user id from jwt token - * @returns {String} user id. + * Function to list users by external id. + * @param {Integer} externalId the legacy user id + * @returns {Array} the users found */ -async function getUserIds (userId) { +async function listUsersByExternalId (externalId) { const token = await getM2MUbahnToken() const q = { enrich: true, externalProfile: { organizationId: config.ORG_ID, - externalId: userId + externalId } } const url = `${config.TC_API}/users?${encodeQueryString(q)}` @@ -617,21 +660,21 @@ async function getUserIds (userId) { .set('Authorization', `Bearer ${token}`) .set('Content-Type', 'application/json') .set('Accept', 'application/json') - localLogger.debug({ context: 'getUserIds', message: `response body: ${JSON.stringify(res.body)}` }) + localLogger.debug({ context: 'listUserByExternalId', message: `response body: ${JSON.stringify(res.body)}` }) return res.body } /** - * Function to get user id - * @param {Integer} userId user id from jwt token - * @returns {String} user id. + * Function to get user by external id. + * @param {Integer} externalId the legacy user id + * @returns {Object} the user */ -async function getUserId (userId) { - const ids = await getUserIds(userId) - if (_.isEmpty(ids)) { - throw new errors.NotFoundError(`userId: ${userId} "user" not found`) +async function getUserByExternalId (externalId) { + const users = await listUsersByExternalId(externalId) + if (_.isEmpty(users)) { + throw new errors.NotFoundError(`externalId: ${externalId} "user" not found`) } - return ids[0].id + return users[0] } /** @@ -883,7 +926,7 @@ async function getSkillById (skillId) { } /** - * Encapsulate the getUserId function. + * Encapsulate the getUserByExternalId function. * Make sure a user exists in ubahn(/v5/users) and return the id of the user. * * In the case the user does not exist in /v5/users but can be found in /v3/users @@ -894,7 +937,7 @@ async function getSkillById (skillId) { */ async function ensureUbahnUserId (currentUser) { try { - return await getUserId(currentUser.userId) + return (await getUserByExternalId(currentUser.userId)).id } catch (err) { if (!(err instanceof errors.NotFoundError)) { throw err @@ -916,6 +959,25 @@ async function ensureJobById (jobId) { return models.Job.findById(jobId) } +/** + * Ensure resource booking with specific id exists. + * + * @param {String} resourceBookingId the resourceBooking id + * @returns {Object} the resourceBooking data + */ +async function ensureResourceBookingById (resourceBookingId) { + return models.ResourceBooking.findById(resourceBookingId) +} + +/** + * Ensure work period with specific id exists. + * @param {String} workPeriodId the workPeriod id + * @returns the workPeriod data + */ +async function ensureWorkPeriodById (workPeriodId) { + return models.WorkPeriod.findById(workPeriodId) +} + /** * Ensure user with specific id exists. * @@ -1118,6 +1180,124 @@ async function deleteProjectMember (currentUser, projectId, projectMemberId) { } } +/** + * Create a new challenge + * + * @param {Object} data challenge data + * @param {String} token m2m token + * @returns {Object} the challenge created + */ +async function createChallenge (data, token) { + if (!token) { + token = await getM2MToken() + } + const url = `${config.TC_API}/challenges` + localLogger.debug({ context: 'createChallenge', message: `EndPoint: POST ${url}` }) + localLogger.debug({ context: 'createChallenge', message: `Request Body: ${JSON.stringify(data)}` }) + const { body: challenge, status: httpStatus } = await request + .post(url) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(data) + localLogger.debug({ context: 'createChallenge', message: `Status Code: ${httpStatus}` }) + localLogger.debug({ context: 'createChallenge', message: `Response Body: ${JSON.stringify(challenge)}` }) + return challenge +} + +/** + * Update a challenge + * + * @param {String} challengeId id of the challenge + * @param {Object} data challenge data + * @param {String} token m2m token + * @returns {Object} the challenge updated + */ +async function updateChallenge (challengeId, data, token) { + if (!token) { + token = await getM2MToken() + } + const url = `${config.TC_API}/challenges/${challengeId}` + localLogger.debug({ context: 'updateChallenge', message: `EndPoint: PATCH ${url}` }) + localLogger.debug({ context: 'updateChallenge', message: `Request Body: ${JSON.stringify(data)}` }) + const { body: challenge, status: httpStatus } = await request + .patch(url) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(data) + localLogger.debug({ context: 'updateChallenge', message: `Status Code: ${httpStatus}` }) + localLogger.debug({ context: 'updateChallenge', message: `Response Body: ${JSON.stringify(challenge)}` }) + return challenge +} + +/** + * Create a challenge resource + * + * @param {Object} data resource + * @param {String} token m2m token + * @returns {Object} the resource created + */ +async function createChallengeResource (data, token) { + if (!token) { + token = await getM2MToken() + } + const url = `${config.TC_API}/resources` + localLogger.debug({ context: 'createChallengeResource', message: `EndPoint: POST ${url}` }) + localLogger.debug({ context: 'createChallengeResource', message: `Request Body: ${JSON.stringify(data)}` }) + const { body: resource, status: httpStatus } = await request + .post(url) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(data) + localLogger.debug({ context: 'createChallengeResource', message: `Status Code: ${httpStatus}` }) + localLogger.debug({ context: 'createChallengeResource', message: `Response Body: ${JSON.stringify(resource)}` }) + return resource +} + +/** + * 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<{startDate:Date, endDate:Date, daysWorked:number}>} information about workPeriods + */ +function extractWorkPeriods (start, end) { + // calculate maximum possible 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) + const startDay = startDate.get('day') + startDate.set('day', 0).startOf('day') + + const endDate = moment(end) + 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, @@ -1138,6 +1318,7 @@ module.exports = { } return ensureUbahnUserId({ userId }) }, + getUserByExternalId, getM2MToken, getM2MUbahnToken, postEvent, @@ -1150,7 +1331,9 @@ module.exports = { getTopcoderSkills, getSkillById, ensureJobById, + ensureResourceBookingById, ensureUserById, + ensureWorkPeriodById, getAuditM2Muser, checkIsMemberOfProject, getMemberDetailsByHandles, @@ -1158,5 +1341,9 @@ module.exports = { createProjectMember, listProjectMembers, listProjectMemberInvites, - deleteProjectMember + deleteProjectMember, + createChallenge, + updateChallenge, + createChallengeResource, + extractWorkPeriods } diff --git a/src/controllers/TeamController.js b/src/controllers/TeamController.js index 6cf1a6b4..b8f7c149 100644 --- a/src/controllers/TeamController.js +++ b/src/controllers/TeamController.js @@ -83,6 +83,15 @@ async function deleteMember (req, res) { res.status(HttpStatus.NO_CONTENT).end() } +/** + * Return details about the current user. + * @param req the request + * @param res the response + */ +async function getMe (req, res) { + res.send(await service.getMe(req.authUser)) +} + module.exports = { searchTeams, getTeam, @@ -91,5 +100,6 @@ module.exports = { addMembers, searchMembers, searchInvites, - deleteMember + deleteMember, + getMe } diff --git a/src/controllers/WorkPeriodController.js b/src/controllers/WorkPeriodController.js new file mode 100644 index 00000000..8a54defa --- /dev/null +++ b/src/controllers/WorkPeriodController.js @@ -0,0 +1,72 @@ +/** + * Controller for WorkPeriod endpoints + */ +const HttpStatus = require('http-status-codes') +const service = require('../services/WorkPeriodService') +const helper = require('../common/helper') + +/** + * Get workPeriod by id + * @param req the request + * @param res the response + */ +async function getWorkPeriod (req, res) { + res.send(await service.getWorkPeriod(req.authUser, req.params.id, req.query.fromDb)) +} + +/** + * Create workPeriod + * @param req the request + * @param res the response + */ +async function createWorkPeriod (req, res) { + res.send(await service.createWorkPeriod(req.authUser, req.body)) +} + +/** + * Partially update workPeriod by id + * @param req the request + * @param res the response + */ +async function partiallyUpdateWorkPeriod (req, res) { + res.send(await service.partiallyUpdateWorkPeriod(req.authUser, req.params.id, req.body)) +} + +/** + * Fully update workPeriod by id + * @param req the request + * @param res the response + */ +async function fullyUpdateWorkPeriod (req, res) { + res.send(await service.fullyUpdateWorkPeriod(req.authUser, req.params.id, req.body)) +} + +/** + * Delete workPeriod by id + * @param req the request + * @param res the response + */ +async function deleteWorkPeriod (req, res) { + await service.deleteWorkPeriod(req.authUser, req.params.id) + res.status(HttpStatus.NO_CONTENT).end() +} + +/** + * Search workPeriods + * @param req the request + * @param res the response + */ +async function searchWorkPeriods (req, res) { + const result = await service.searchWorkPeriods(req.authUser, req.query) + helper.setResHeaders(req, res, result) + res.send(result.result) +} + +module.exports = { + getWorkPeriod, + createWorkPeriod, + partiallyUpdateWorkPeriod, + fullyUpdateWorkPeriod, + deleteWorkPeriod, + searchWorkPeriods +} diff --git a/src/controllers/WorkPeriodPaymentController.js b/src/controllers/WorkPeriodPaymentController.js new file mode 100644 index 00000000..93f5c046 --- /dev/null +++ b/src/controllers/WorkPeriodPaymentController.js @@ -0,0 +1,61 @@ +/** + * Controller for WorkPeriodPayment endpoints + */ +const service = require('../services/WorkPeriodPaymentService') +const helper = require('../common/helper') +const config = require('config') + +/** + * Get workPeriodPayment by id + * @param req the request + * @param res the response + */ +async function getWorkPeriodPayment (req, res) { + res.send(await service.getWorkPeriodPayment(req.authUser, req.params.id, req.query.fromDb)) +} + +/** + * Create workPeriodPayment + * @param req the request + * @param res the response + */ +async function createWorkPeriodPayment (req, res) { + res.send(await service.createWorkPeriodPayment(req.authUser, req.body, { paymentProcessingSwitch: config.PAYMENT_PROCESSING_SWITCH })) +} + +/** + * Partially update workPeriodPayment by id + * @param req the request + * @param res the response + */ +async function partiallyUpdateWorkPeriodPayment (req, res) { + res.send(await service.partiallyUpdateWorkPeriodPayment(req.authUser, req.params.id, req.body)) +} + +/** + * Fully update workPeriodPayment by id + * @param req the request + * @param res the response + */ +async function fullyUpdateWorkPeriodPayment (req, res) { + res.send(await service.fullyUpdateWorkPeriodPayment(req.authUser, req.params.id, req.body)) +} + +/** + * Search workPeriodPayments + * @param req the request + * @param res the response + */ +async function searchWorkPeriodPayments (req, res) { + const result = await service.searchWorkPeriodPayments(req.authUser, req.query) + helper.setResHeaders(req, res, result) + res.send(result.result) +} + +module.exports = { + getWorkPeriodPayment, + createWorkPeriodPayment, + partiallyUpdateWorkPeriodPayment, + fullyUpdateWorkPeriodPayment, + searchWorkPeriodPayments +} diff --git a/src/eventHandlers/ResourceBookingEventHandler.js b/src/eventHandlers/ResourceBookingEventHandler.js index 69dbe1dd..8145ba49 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') + // find which workperiods' daysWorked property is preset and exceeds the possible maximum + workPeriodsToUpdate = _.differenceWith(workPeriodsToUpdate, workPeriods, (a, b) => b.startDate === a.startDate && _.defaultTo(b.daysWorked, a.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 that affect work periods - 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}>} periods work period data + * @param {string} resourceBookingId resourceBookingId of work period + * @returns {undefined} + */ +async function _createWorkPeriods (periods, resourceBookingId) { + await Promise.all(_.map(periods, async period => await WorkPeriodService.createWorkPeriod(helper.getAuditM2Muser(), + { + resourceBookingId: resourceBookingId, + startDate: period.startDate, + endDate: period.endDate, + daysWorked: null, + paymentStatus: 'pending' + }))) +} + +/** + * Calls WorkPeriodService to update workPeriods + * @param {Array<{daysWorked:number}>} periods work period data + * @returns {undefined} + */ +async function _updateWorkPeriods (periods) { + await Promise.all(_.map(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) { + await Promise.all(_.map(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/init-db.js b/src/init-db.js index 95b608a8..7d09ccd5 100644 --- a/src/init-db.js +++ b/src/init-db.js @@ -2,15 +2,39 @@ * Sync the database models to db tables. */ const config = require('config') +const fs = require('fs') const models = require('./models') const logger = require('./common/logger') +// the directory at which migration scripts are located +const MigrationsDirPath = './migrations' + +/** + * List the filenames of the migration files. + * + * @returns {Array} the list of filenames + */ +function listMigrationFiles () { + const filenames = fs.readdirSync(MigrationsDirPath) + return filenames +} + const initDB = async () => { if (process.argv[2] === 'force') { await models.sequelize.dropSchema(config.DB_SCHEMA_NAME) } await models.sequelize.createSchema(config.DB_SCHEMA_NAME) + // define SequelizeMeta table + const SequelizeMeta = await models.sequelize.define('SequelizeMeta', { + name: { + type: models.Sequelize.STRING(255), + allowNull: false + } + }, { timestamps: false }) + // re-init all tables including the SequelizeMeta table await models.sequelize.sync({ force: true }) + // add filenames of existing migration scripts to the SequelizeMeta table + await SequelizeMeta.bulkCreate(listMigrationFiles().map(filename => ({ name: filename }))) } if (!module.parent) { diff --git a/src/models/ResourceBooking.js b/src/models/ResourceBooking.js index 2b6b0b7f..58dc5454 100644 --- a/src/models/ResourceBooking.js +++ b/src/models/ResourceBooking.js @@ -10,6 +10,7 @@ module.exports = (sequelize) => { */ static associate (models) { ResourceBooking.belongsTo(models.Job, { foreignKey: 'jobId' }) + ResourceBooking.hasMany(models.WorkPeriod, { foreignKey: 'resourceBookingId' }) } /** @@ -57,11 +58,11 @@ module.exports = (sequelize) => { }, startDate: { field: 'start_date', - type: Sequelize.DATE + type: Sequelize.DATEONLY }, endDate: { field: 'end_date', - type: Sequelize.DATE + type: Sequelize.DATEONLY }, memberRate: { field: 'member_rate', @@ -76,6 +77,10 @@ module.exports = (sequelize) => { type: Sequelize.STRING(255), allowNull: false }, + billingAccountId: { + field: 'billing_account_id', + type: Sequelize.BIGINT + }, createdBy: { field: 'created_by', type: Sequelize.UUID, diff --git a/src/models/WorkPeriod.js b/src/models/WorkPeriod.js new file mode 100644 index 00000000..455818b5 --- /dev/null +++ b/src/models/WorkPeriod.js @@ -0,0 +1,147 @@ +const { Sequelize, Model } = require('sequelize') +const config = require('config') +const errors = require('../common/errors') + +module.exports = (sequelize) => { + class WorkPeriod extends Model { + /** + * Create association between models + * @param {Object} models the database models + */ + static associate (models) { + WorkPeriod._models = models + WorkPeriod.belongsTo(models.ResourceBooking, { foreignKey: 'resourceBookingId' }) + WorkPeriod.hasMany(models.WorkPeriodPayment, { as: 'payments', foreignKey: 'workPeriodId' }) + } + + /** + * Get work period by id + * @param {String} id the work period id + * @param {Object} options { withPayments: true/false } whether contains payments + * @returns {WorkPeriod} the work period instance + */ + static async findById (id, options = { withPayments: false }) { + const criteria = { + where: { + id + } + } + if (options.withPayments) { + criteria.include = [{ + model: WorkPeriod._models.WorkPeriodPayment, + as: 'payments', + required: false + }] + } + const workPeriod = await WorkPeriod.findOne(criteria) + if (!workPeriod) { + throw new errors.NotFoundError(`id: ${id} "WorkPeriod" doesn't exists.`) + } + return workPeriod + } + } + WorkPeriod.init( + { + id: { + type: Sequelize.UUID, + primaryKey: true, + allowNull: false, + defaultValue: Sequelize.UUIDV4 + }, + resourceBookingId: { + field: 'resource_booking_id', + type: Sequelize.UUID, + allowNull: false + }, + userHandle: { + field: 'user_handle', + type: Sequelize.STRING(50), + allowNull: false + }, + projectId: { + field: 'project_id', + type: Sequelize.INTEGER, + allowNull: false + }, + startDate: { + field: 'start_date', + type: Sequelize.DATEONLY, + allowNull: false + }, + endDate: { + field: 'end_date', + type: Sequelize.DATEONLY, + allowNull: false + }, + daysWorked: { + field: 'days_worked', + type: Sequelize.INTEGER + }, + memberRate: { + field: 'member_rate', + type: Sequelize.FLOAT + }, + customerRate: { + field: 'customer_rate', + type: Sequelize.FLOAT + }, + paymentStatus: { + field: 'payment_status', + type: Sequelize.STRING(50), + allowNull: false + }, + createdBy: { + field: 'created_by', + type: Sequelize.UUID, + allowNull: false + }, + updatedBy: { + field: 'updated_by', + type: Sequelize.UUID + }, + createdAt: { + field: 'created_at', + type: Sequelize.DATE + }, + updatedAt: { + field: 'updated_at', + type: Sequelize.DATE + }, + deletedAt: { + field: 'deleted_at', + type: Sequelize.DATE + } + }, + { + schema: config.DB_SCHEMA_NAME, + sequelize, + tableName: 'work_periods', + paranoid: true, + deletedAt: 'deletedAt', + createdAt: 'createdAt', + updatedAt: 'updatedAt', + timestamps: true, + defaultScope: { + attributes: { + exclude: ['deletedAt'] + } + }, + hooks: { + afterCreate: (workPeriod) => { + delete workPeriod.dataValues.deletedAt + } + }, + indexes: [ + { + unique: true, + fields: ['resource_booking_id', 'start_date', 'end_date'], + where: { + deleted_at: null + } + } + ] + } + ) + + return WorkPeriod +} diff --git a/src/models/WorkPeriodPayment.js b/src/models/WorkPeriodPayment.js new file mode 100644 index 00000000..3683faf0 --- /dev/null +++ b/src/models/WorkPeriodPayment.js @@ -0,0 +1,109 @@ +const { Sequelize, Model } = require('sequelize') +const config = require('config') +const errors = require('../common/errors') + +module.exports = (sequelize) => { + class WorkPeriodPayment extends Model { + /** + * Create association between models + * @param {Object} models the database models + */ + static associate (models) { + WorkPeriodPayment.belongsTo(models.WorkPeriod, { foreignKey: 'workPeriodId' }) + } + + /** + * Get work period by id + * @param {String} id the work period id + * @returns {WorkPeriodPayment} the work period payment instance + */ + static async findById (id) { + const workPeriodPayment = await WorkPeriodPayment.findOne({ + where: { + id + } + }) + if (!workPeriodPayment) { + throw new errors.NotFoundError(`id: ${id} "WorkPeriodPayment" doesn't exists`) + } + return workPeriodPayment + } + } + WorkPeriodPayment.init( + { + id: { + type: Sequelize.UUID, + primaryKey: true, + allowNull: false, + defaultValue: Sequelize.UUIDV4 + }, + workPeriodId: { + field: 'work_period_id', + type: Sequelize.UUID, + allowNull: false + }, + challengeId: { + field: 'challenge_id', + type: Sequelize.UUID, + allowNull: false + }, + amount: { + type: Sequelize.DOUBLE + }, + status: { + type: Sequelize.ENUM( + 'completed', + 'cancelled' + ), + allowNull: false + }, + billingAccountId: { + field: 'billing_account_id', + type: Sequelize.BIGINT + }, + createdBy: { + field: 'created_by', + type: Sequelize.UUID, + allowNull: false + }, + updatedBy: { + field: 'updated_by', + type: Sequelize.UUID + }, + createdAt: { + field: 'created_at', + type: Sequelize.DATE + }, + updatedAt: { + field: 'updated_at', + type: Sequelize.DATE + }, + deletedAt: { + field: 'deleted_at', + type: Sequelize.DATE + } + }, + { + schema: config.DB_SCHEMA_NAME, + sequelize, + tableName: 'work_period_payments', + paranoid: true, + deletedAt: 'deletedAt', + createdAt: 'createdAt', + updatedAt: 'updatedAt', + timestamps: true, + defaultScope: { + attributes: { + exclude: ['deletedAt'] + } + }, + hooks: { + afterCreate: (workPeriodPayment) => { + delete workPeriodPayment.dataValues.deletedAt + } + } + } + ) + + return WorkPeriodPayment +} diff --git a/src/routes/TeamRoutes.js b/src/routes/TeamRoutes.js index 3df14b0c..f5d062c6 100644 --- a/src/routes/TeamRoutes.js +++ b/src/routes/TeamRoutes.js @@ -28,6 +28,14 @@ module.exports = { scopes: [constants.Scopes.READ_TAAS_TEAM] } }, + '/taas-teams/me': { + get: { + controller: 'TeamController', + method: 'getMe', + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] + } + }, '/taas-teams/:id': { get: { controller: 'TeamController', diff --git a/src/routes/WorkPeriodPaymentRoutes.js b/src/routes/WorkPeriodPaymentRoutes.js new file mode 100644 index 00000000..dcc284eb --- /dev/null +++ b/src/routes/WorkPeriodPaymentRoutes.js @@ -0,0 +1,41 @@ +/** + * Contains workPeriodPayment routes + */ +const constants = require('../../app-constants') + +module.exports = { + '/work-period-payments': { + post: { + controller: 'WorkPeriodPaymentController', + method: 'createWorkPeriodPayment', + auth: 'jwt', + scopes: [constants.Scopes.CREATE_WORK_PERIOD_PAYMENT, constants.Scopes.ALL_WORK_PERIOD_PAYMENT] + }, + get: { + controller: 'WorkPeriodPaymentController', + method: 'searchWorkPeriodPayments', + auth: 'jwt', + scopes: [constants.Scopes.READ_WORK_PERIOD_PAYMENT, constants.Scopes.ALL_WORK_PERIOD_PAYMENT] + } + }, + '/work-period-payments/:id': { + get: { + controller: 'WorkPeriodPaymentController', + method: 'getWorkPeriodPayment', + auth: 'jwt', + scopes: [constants.Scopes.READ_WORK_PERIOD_PAYMENT, constants.Scopes.ALL_WORK_PERIOD_PAYMENT] + }, + put: { + controller: 'WorkPeriodPaymentController', + method: 'fullyUpdateWorkPeriodPayment', + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_WORK_PERIOD_PAYMENT, constants.Scopes.ALL_WORK_PERIOD_PAYMENT] + }, + patch: { + controller: 'WorkPeriodPaymentController', + method: 'partiallyUpdateWorkPeriodPayment', + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_WORK_PERIOD_PAYMENT, constants.Scopes.ALL_WORK_PERIOD_PAYMENT] + } + } +} diff --git a/src/routes/WorkPeriodRoutes.js b/src/routes/WorkPeriodRoutes.js new file mode 100644 index 00000000..7f84b5b0 --- /dev/null +++ b/src/routes/WorkPeriodRoutes.js @@ -0,0 +1,47 @@ +/** + * Contains workPeriod routes + */ +const constants = require('../../app-constants') + +module.exports = { + '/work-periods': { + post: { + controller: 'WorkPeriodController', + method: 'createWorkPeriod', + auth: 'jwt', + scopes: [constants.Scopes.CREATE_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] + }, + get: { + controller: 'WorkPeriodController', + method: 'searchWorkPeriods', + auth: 'jwt', + scopes: [constants.Scopes.READ_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] + } + }, + '/work-periods/:id': { + get: { + controller: 'WorkPeriodController', + method: 'getWorkPeriod', + auth: 'jwt', + scopes: [constants.Scopes.READ_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] + }, + put: { + controller: 'WorkPeriodController', + method: 'fullyUpdateWorkPeriod', + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] + }, + patch: { + controller: 'WorkPeriodController', + method: 'partiallyUpdateWorkPeriod', + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] + }, + delete: { + controller: 'WorkPeriodController', + method: 'deleteWorkPeriod', + auth: 'jwt', + scopes: [constants.Scopes.DELETE_WORK_PERIOD, constants.Scopes.ALL_WORK_PERIOD] + } + } +} diff --git a/src/services/PaymentService.js b/src/services/PaymentService.js new file mode 100644 index 00000000..7d714f75 --- /dev/null +++ b/src/services/PaymentService.js @@ -0,0 +1,170 @@ +/** + * This service provides operations of PaymentService. + */ + +const _ = require('lodash') +const Joi = require('joi') +const config = require('config') +const helper = require('../common/helper') +const logger = require('../common/logger') +const constants = require('../../app-constants') + +const localLogger = { + debug: (message) => logger.debug({ component: 'PaymentService', context: message.context, message: message.message }), + error: (message) => logger.error({ component: 'PaymentService', context: message.context, message: message.message }), + info: (message) => logger.info({ component: 'PaymentService', context: message.context, message: message.message }) +} + +/** + * Create payment + * @param {Object} options the user who perform this operation + * @param {Object} options.projectId the user who perform this operation + * @param {Object} options.userHandle the user who perform this operation + * @param {Object} options.amount the user who perform this operation + * @param {Object} options.billingAccountId the user who perform this operation + * @param {Object} options.name the user who perform this operation + * @param {Object} options.description the user who perform this operation + * @returns {Object} the completed challenge + */ +async function createPayment (options) { + if (_.isUndefined(options.name)) { + options.name = `TaaS payment for user ${options.userHandle} in project ${options.projectId}` + } + if (_.isUndefined(options.description)) { + options.description = `TaaS payment for user ${options.userHandle} in project ${options.projectId}` + } + localLogger.info({ context: 'createPayment', message: 'generating M2MToken' }) + const token = await helper.getM2MToken() + localLogger.info({ context: 'createPayment', message: 'M2MToken is generated' }) + const challengeId = await createChallenge(options, token) + await addResourceToChallenge(challengeId, options.userHandle, token) + await activateChallenge(challengeId, token) + const completedChallenge = await closeChallenge(challengeId, token) + return completedChallenge +} + +createPayment.schema = Joi.object().keys({ + options: Joi.object().keys({ + projectId: Joi.number().integer().required(), + userHandle: Joi.string().required(), + amount: Joi.number().positive().required(), + billingAccountId: Joi.number().allow(null), + name: Joi.string(), + description: Joi.string() + }).required() +}).required() + +/** + * Create a new challenge. + * @param {Object} challenge the challenge to create + * @param {String} token m2m token + * @returns {Number} the created challenge id + */ +async function createChallenge (challenge, token) { + localLogger.info({ context: 'createChallenge', message: 'creating new challenge' }) + const body = { + status: constants.ChallengeStatus.DRAFT, + projectId: challenge.projectId, + name: challenge.name, + description: challenge.description, + descriptionFormat: 'markdown', + typeId: config.TYPE_ID_TASK, + trackId: config.DEFAULT_TRACK_ID, + timelineTemplateId: config.DEFAULT_TIMELINE_TEMPLATE_ID, + prizeSets: [{ + type: 'placement', + prizes: [{ type: 'USD', value: challenge.amount }] + }], + legacy: { + pureV5Task: true + }, + tags: ['Other'], + startDate: new Date() + } + + if (challenge.billingAccountId) { + body.billing = { + billingAccountId: challenge.billingAccountId, + markup: 0 // for TaaS payments we always use 0 markup + } + } + try { + const response = await helper.createChallenge(body, token) + const challengeId = _.get(response, 'id') + localLogger.info({ context: 'createChallenge', message: `Challenge with id ${challengeId} is created` }) + return challengeId + } catch (err) { + localLogger.error({ context: 'createChallenge', message: `Status Code: ${err.status}` }) + localLogger.error({ context: 'createChallenge', message: err.response.text }) + throw err + } +} + +/** + * adds the resource to the topcoder challenge + * @param {String} id the challenge id + * @param {String} handle the user handle to add + * @param {String} token m2m token + */ +async function addResourceToChallenge (id, handle, token) { + localLogger.info({ context: 'addResourceToChallenge', message: `adding resource to challenge ${id}` }) + try { + const body = { + challengeId: id, + memberHandle: handle, + roleId: config.ROLE_ID_SUBMITTER + } + await helper.createChallengeResource(body, token) + localLogger.info({ context: 'addResourceToChallenge', message: `${handle} added to challenge ${id}` }) + } catch (err) { + localLogger.error({ context: 'addResourceToChallenge', message: `Status Code: ${err.status}` }) + localLogger.error({ context: 'addResourceToChallenge', message: err.response.text }) + throw err + } +} + +/** + * activates the topcoder challenge + * @param {String} id the challenge id + * @param {String} token m2m token + */ +async function activateChallenge (id, token) { + localLogger.info({ context: 'activateChallenge', message: `Activating challenge ${id}` }) + try { + const body = { + status: constants.ChallengeStatus.ACTIVE + } + await helper.updateChallenge(id, body, token) + localLogger.info({ context: 'activateChallenge', message: `Challenge ${id} is activated successfully.` }) + } catch (err) { + localLogger.error({ context: 'activateChallenge', message: `Status Code: ${err.status}` }) + localLogger.error({ context: 'activateChallenge', message: err.response.text }) + throw err + } +} + +/** + * closes the topcoder challenge + * @param {String} id the challenge id + * @param {String} token m2m token + * @returns {Object} the closed challenge + */ +async function closeChallenge (id, token) { + localLogger.info({ context: 'closeChallenge', message: `Closing challenge ${id}` }) + try { + const body = { + status: constants.ChallengeStatus.COMPLETED + } + const response = await helper.updateChallenge(id, body, token) + localLogger.info({ context: 'closeChallenge', message: `Challenge ${id} is closed successfully.` }) + return response + } catch (err) { + localLogger.error({ context: 'closeChallenge', message: `Status Code: ${err.status}` }) + localLogger.error({ context: 'closeChallenge', message: err.response.text }) + throw err + } +} + +module.exports = { + createPayment +} diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index 120b9539..4fef4e46 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -3,7 +3,7 @@ */ const _ = require('lodash') -const Joi = require('joi') +const Joi = require('joi').extend(require('@joi/date')) const config = require('config') const HttpStatus = require('http-status-codes') const { Op } = require('sequelize') @@ -12,8 +12,10 @@ const helper = require('../common/helper') const logger = require('../common/logger') const errors = require('../common/errors') const models = require('../models') +const moment = require('moment') const ResourceBooking = models.ResourceBooking +const WorkPeriod = models.WorkPeriod const esClient = helper.getESClient() /** @@ -42,6 +44,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,23 +159,31 @@ 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), + startDate: Joi.date().format('YYYY-MM-DD').allow(null), + endDate: Joi.date().format('YYYY-MM-DD').when('startDate', { + is: Joi.exist(), + then: Joi.date().format('YYYY-MM-DD').allow(null).min(Joi.ref('startDate') + ).messages({ + 'date.min': 'endDate cannot be earlier than startDate' + }), + otherwise: Joi.date().format('YYYY-MM-DD').allow(null) + }), memberRate: Joi.number().allow(null), customerRate: Joi.number().allow(null), - rateType: Joi.rateType().required() + rateType: Joi.rateType().required(), + billingAccountId: Joi.number().allow(null) }).required() }).required() /** * 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,20 +194,21 @@ 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) const updated = await resourceBooking.update(data) await helper.postEvent(config.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue }) - const result = _.assign(resourceBooking.dataValues, data) - return result + return updated.dataValues } /** * 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,20 +219,28 @@ partiallyUpdateResourceBooking.schema = Joi.object().keys({ currentUser: Joi.object().required(), id: Joi.string().uuid().required(), data: Joi.object().keys({ - status: Joi.jobStatus(), - startDate: Joi.date().allow(null), - endDate: Joi.date().allow(null), + status: Joi.resourceBookingStatus(), + startDate: Joi.date().format('YYYY-MM-DD').allow(null), + endDate: Joi.date().format('YYYY-MM-DD').when('startDate', { + is: Joi.exist(), + then: Joi.date().format('YYYY-MM-DD').allow(null).min(Joi.ref('startDate') + ).messages({ + 'date.min': 'endDate cannot be earlier than startDate' + }), + otherwise: Joi.date().format('YYYY-MM-DD').allow(null) + }), memberRate: Joi.number().allow(null), customerRate: Joi.number().allow(null), - rateType: Joi.rateType() + rateType: Joi.rateType(), + billingAccountId: Joi.number().allow(null) }).required() }).required() /** * 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) { @@ -195,19 +258,27 @@ fullyUpdateResourceBooking.schema = Joi.object().keys({ projectId: Joi.number().integer().required(), 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), + startDate: Joi.date().format('YYYY-MM-DD').allow(null).default(null), + endDate: Joi.date().format('YYYY-MM-DD').when('startDate', { + is: Joi.exist(), + then: Joi.date().format('YYYY-MM-DD').allow(null).default(null).min(Joi.ref('startDate') + ).messages({ + 'date.min': 'endDate cannot be earlier than startDate' + }), + otherwise: Joi.date().format('YYYY-MM-DD').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(), + billingAccountId: Joi.number().allow(null).default(null) }).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 +286,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 +301,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 }) { @@ -287,7 +360,13 @@ async function searchResourceBookings (currentUser, criteria, options = { return sort } } - + // change the date format to match with index schema + if (criteria.startDate) { + criteria.startDate = moment(criteria.startDate).format('YYYY-MM-DD') + } + if (criteria.endDate) { + criteria.endDate = moment(criteria.endDate).format('YYYY-MM-DD') + } _.each(_.pick(criteria, ['status', 'startDate', 'endDate', 'rateType', 'projectId', 'jobId', 'userId']), (value, key) => { esQuery.body.query.bool.must.push({ term: { @@ -323,7 +402,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,9 +431,9 @@ 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(), - startDate: Joi.date(), - endDate: Joi.date(), + status: Joi.resourceBookingStatus(), + startDate: Joi.date().format('YYYY-MM-DD'), + endDate: Joi.date().format('YYYY-MM-DD'), rateType: Joi.rateType(), jobId: Joi.string().uuid(), userId: Joi.string().uuid(), diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 640791a2..0519543e 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -513,6 +513,21 @@ deleteMember.schema = Joi.object().keys({ projectMemberId: Joi.number().integer().required() }).required() +/** + * Return details about the current user. + * + * @param {Object} currentUser the user who perform this operation. + * @params {Object} criteria the search criteria + * @returns {Object} the user data for current user + */ +async function getMe (currentUser) { + return helper.getUserByExternalId(currentUser.userId) +} + +getMe.schema = Joi.object().keys({ + currentUser: Joi.object().required() +}).required() + module.exports = { searchTeams, getTeam, @@ -521,5 +536,6 @@ module.exports = { addMembers, searchMembers, searchInvites, - deleteMember + deleteMember, + getMe } diff --git a/src/services/WorkPeriodPaymentService.js b/src/services/WorkPeriodPaymentService.js new file mode 100644 index 00000000..e8694c76 --- /dev/null +++ b/src/services/WorkPeriodPaymentService.js @@ -0,0 +1,352 @@ +/** + * This service provides operations of WorkPeriod. + */ + +const _ = require('lodash') +const Joi = require('joi') +const config = require('config') +const HttpStatus = require('http-status-codes') +const { Op } = require('sequelize') +const uuid = require('uuid') +const moment = require('moment') +const helper = require('../common/helper') +const logger = require('../common/logger') +const errors = require('../common/errors') +const constants = require('../../app-constants') +const models = require('../models') +const PaymentService = require('./PaymentService') + +const WorkPeriodPayment = models.WorkPeriodPayment +const esClient = helper.getESClient() + +/** + * Check user permission for creating, updating or getting + * work period payment. + * Only Booking Manager, Admin, and M2M has access to create, view or update payments + * @param {Object} currentUser the user who perform this operation. + * @returns {undefined} + */ +async function _checkUserPermissionForCRUWorkPeriodPayment (currentUser) { + if (!currentUser.hasManagePermission && !currentUser.isMachine) { + throw new errors.ForbiddenError('You are not allowed to perform this action!') + } +} + +/** + * Get workPeriodPayment by id + * @param {Object} currentUser the user who perform this operation. + * @param {String} id the workPeriodPayment id + * @param {Boolean} fromDb flag if query db for data or not + * @returns {Object} the workPeriodPayment + */ +async function getWorkPeriodPayment (currentUser, id, fromDb = false) { + // check user permission + await _checkUserPermissionForCRUWorkPeriodPayment(currentUser) + if (!fromDb) { + try { + const workPeriod = await esClient.search({ + index: config.esConfig.ES_INDEX_WORK_PERIOD, + _source: 'payments', + body: { + query: { + nested: { + path: 'payments', + query: { + match: { 'payments.id': id } + } + } + } + } + }) + + if (!workPeriod.body.hits.total.value) { + throw new errors.NotFoundError() + } + const workPeriodPaymentRecord = _.find(workPeriod.body.hits.hits[0]._source.payments, { id }) + return workPeriodPaymentRecord + } catch (err) { + if (err.httpStatus === HttpStatus.NOT_FOUND) { + throw new errors.NotFoundError(`id: ${id} "WorkPeriodPayment" not found`) + } + if (err.httpStatus === HttpStatus.FORBIDDEN) { + throw err + } + logger.logFullError(err, { component: 'WorkPeriodPaymentService', context: 'getWorkPeriodPayment' }) + } + } + logger.info({ component: 'WorkPeriodPaymentService', context: 'getWorkPeriodPayment', message: 'try to query db for data' }) + const workPeriodPayment = await WorkPeriodPayment.findById(id) + + return workPeriodPayment +} + +getWorkPeriodPayment.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().guid().required(), + fromDb: Joi.boolean() +}).required() + +/** + * Create workPeriodPayment + * @param {Object} currentUser the user who perform this operation + * @param {Object} workPeriodPayment the workPeriodPayment to be created + * @param {Object} options the extra options to control the function + * @returns {Object} the created workPeriodPayment + */ +async function createWorkPeriodPayment (currentUser, workPeriodPayment, options = { paymentProcessingSwitch: 'OFF' }) { + // check permission + await _checkUserPermissionForCRUWorkPeriodPayment(currentUser) + + const { projectId, userHandle, endDate, resourceBookingId } = await helper.ensureWorkPeriodById(workPeriodPayment.workPeriodId) // ensure work period exists + + // get billingAccountId from corresponding resource booking + const correspondingResourceBooking = await helper.ensureResourceBookingById(resourceBookingId) + if (!correspondingResourceBooking.billingAccountId) { + throw new errors.ConflictError(`id: ${resourceBookingId} "ResourceBooking" Billing account is not assigned to the resource booking`) + } + workPeriodPayment.billingAccountId = correspondingResourceBooking.billingAccountId + + const paymentChallenge = options.paymentProcessingSwitch === constants.PaymentProcessingSwitch.ON ? (await PaymentService.createPayment({ + projectId, + userHandle, + amount: workPeriodPayment.amount, + name: `TaaS Payment - ${userHandle} - Week Ending ${moment(endDate).format('D/M/YYYY')}`, + description: `TaaS Payment - ${userHandle} - Week Ending ${moment(endDate).format('D/M/YYYY')}`, + billingAccountId: correspondingResourceBooking.billingAccountId + })) : ({ id: '00000000-0000-0000-0000-000000000000' }) + + workPeriodPayment.id = uuid.v4() + workPeriodPayment.challengeId = paymentChallenge.id + workPeriodPayment.createdBy = await helper.getUserId(currentUser.userId) + + let created = null + try { + created = await WorkPeriodPayment.create(workPeriodPayment) + } catch (err) { + if (!_.isUndefined(err.original)) { + throw new errors.BadRequestError(err.original.detail) + } else { + throw err + } + } + + await helper.postEvent(config.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC, created.toJSON()) + return created.dataValues +} + +createWorkPeriodPayment.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + workPeriodPayment: Joi.object().keys({ + workPeriodId: Joi.string().uuid().required(), + amount: Joi.number().greater(0).allow(null), + status: Joi.workPeriodPaymentStatus().default('completed') + }).required(), + options: Joi.object() +}).required() + +/** + * Update workPeriodPayment + * @param {Object} currentUser the user who perform this operation + * @param {String} id the workPeriod id + * @param {Object} data the data to be updated + * @returns {Object} the updated workPeriodPayment + */ +async function updateWorkPeriodPayment (currentUser, id, data) { + // check permission + await _checkUserPermissionForCRUWorkPeriodPayment(currentUser) + + if (data.workPeriodId) { + // ensure work period exists + await helper.ensureWorkPeriodById(data.workPeriodId) + } + const workPeriodPayment = await WorkPeriodPayment.findById(id) + const oldValue = workPeriodPayment.toJSON() + + data.updatedBy = await helper.getUserId(currentUser.userId) + let updated = null + try { + updated = await workPeriodPayment.update(data) + } catch (err) { + if (!_.isUndefined(err.original)) { + throw new errors.BadRequestError(err.original.detail) + } else { + throw err + } + } + + await helper.postEvent(config.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue }) + return updated.dataValues +} + +/** + * Partially update workPeriodPayment by id + * @param {Object} currentUser the user who perform this operation + * @param {String} id the workPeriodPayment id + * @param {Object} data the data to be updated + * @returns {Object} the updated workPeriodPayment + */ +async function partiallyUpdateWorkPeriodPayment (currentUser, id, data) { + return updateWorkPeriodPayment(currentUser, id, data) +} + +partiallyUpdateWorkPeriodPayment.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().uuid().required(), + data: Joi.object().keys({ + workPeriodId: Joi.string().uuid(), + amount: Joi.number().greater(0).allow(null), + status: Joi.workPeriodPaymentStatus() + }).required() +}).required() + +/** + * Fully update workPeriodPayment by id + * @param {Object} currentUser the user who perform this operation + * @param {String} id the workPeriodPayment id + * @param {Object} data the data to be updated + * @returns {Object} the updated workPeriodPayment + */ +async function fullyUpdateWorkPeriodPayment (currentUser, id, data) { + return updateWorkPeriodPayment(currentUser, id, data) +} + +fullyUpdateWorkPeriodPayment.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().uuid().required(), + data: Joi.object().keys({ + workPeriodId: Joi.string().uuid().required(), + amount: Joi.number().greater(0).allow(null), + status: Joi.workPeriodPaymentStatus() + }).required() +}).required() + +/** + * List workPeriodPayments + * @param {Object} currentUser the user who perform this operation. + * @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 searchWorkPeriodPayments (currentUser, criteria, options = { returnAll: false }) { + // check user permission + await _checkUserPermissionForCRUWorkPeriodPayment(currentUser) + + if ((typeof criteria.workPeriodIds) === 'string') { + criteria.workPeriodIds = criteria.workPeriodIds.trim().split(',').map(workPeriodIdRaw => { + const workPeriodId = workPeriodIdRaw.trim() + if (!uuid.validate(workPeriodId)) { + throw new errors.BadRequestError(`workPeriodId ${workPeriodId} is not a valid uuid`) + } + return workPeriodId + }) + } + const page = criteria.page + const perPage = criteria.perPage + try { + const esQuery = { + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + _source: 'payments', + body: { + query: { + nested: { + path: 'payments', + query: { bool: { must: [] } } + } + }, + size: 10000 + // We use a very large number for size, because we can't paginate nested documents + // and in practice there could hardly be so many records to be returned.(also consider we are using filters in the meantime) + // the number is limited by `index.max_result_window`, its default value is 10000, see + // https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-max-result-window + } + } + _.each(_.pick(criteria, ['status', 'workPeriodId']), (value, key) => { + esQuery.body.query.nested.query.bool.must.push({ + term: { + [`payments.${key}`]: { + value + } + } + }) + }) + if (criteria.workPeriodIds) { + esQuery.body.query.nested.query.bool.filter = [{ + terms: { + 'payments.workPeriodId': criteria.workPeriodIds + } + }] + } + logger.debug({ component: 'WorkPeriodPaymentService', context: 'searchWorkPeriodPayment', message: `Query: ${JSON.stringify(esQuery)}` }) + + const { body } = await esClient.search(esQuery) + let payments = _.reduce(body.hits.hits, (acc, workPeriod) => _.concat(acc, workPeriod._source.payments), []) + if (criteria.status) { + payments = _.filter(payments, { status: criteria.status }) + } + payments = _.sortBy(payments, [criteria.sortBy]) + if (criteria.sortOrder === 'desc') { + payments = _.reverse(payments) + } + const total = payments.length + if (!options.returnAll) { + payments = _.slice(payments, (page - 1) * perPage, page * perPage) + } + + return { + total, + page, + perPage, + result: payments + } + } catch (err) { + logger.logFullError(err, { component: 'WorkPeriodPaymentService', context: 'searchWorkPeriodPaymentService' }) + } + logger.info({ component: 'WorkPeriodPaymentService', context: 'searchWorkPeriodPayments', message: 'fallback to DB query' }) + const filter = { [Op.and]: [] } + _.each(_.pick(criteria, ['status', 'workPeriodId']), (value, key) => { + filter[Op.and].push({ [key]: value }) + }) + if (criteria.workPeriodIds) { + filter[Op.and].push({ workPeriodId: criteria.workPeriodIds }) + } + const workPeriodPayments = await WorkPeriodPayment.findAll({ + where: filter, + offset: ((page - 1) * perPage), + limit: perPage, + order: [[criteria.sortBy, criteria.sortOrder]] + }) + return { + fromDb: true, + total: workPeriodPayments.length, + page, + perPage, + result: _.map(workPeriodPayments, workPeriodPayment => { + return workPeriodPayment.dataValues + }) + } +} + +searchWorkPeriodPayments.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + criteria: Joi.object().keys({ + page: Joi.number().integer().min(1).default(1), + perPage: Joi.number().integer().min(1).max(10000).default(20), + sortBy: Joi.string().valid('status', 'amount', 'createdAt', 'updatedAt').default('createdAt'), + sortOrder: Joi.string().valid('desc', 'asc').default('desc'), + status: Joi.workPeriodPaymentStatus(), + workPeriodId: Joi.string().uuid(), + workPeriodIds: Joi.alternatives( + Joi.string(), + Joi.array().items(Joi.string().uuid()) + ) + }).required(), + options: Joi.object() +}).required() + +module.exports = { + getWorkPeriodPayment, + createWorkPeriodPayment, + partiallyUpdateWorkPeriodPayment, + fullyUpdateWorkPeriodPayment, + searchWorkPeriodPayments +} diff --git a/src/services/WorkPeriodService.js b/src/services/WorkPeriodService.js new file mode 100644 index 00000000..92e1deb0 --- /dev/null +++ b/src/services/WorkPeriodService.js @@ -0,0 +1,522 @@ +/** + * This service provides operations of WorkPeriod. + */ + +const _ = require('lodash') +const Joi = require('joi').extend(require('@joi/date')) +const config = require('config') +const HttpStatus = require('http-status-codes') +const { Op } = require('sequelize') +const uuid = require('uuid') +const helper = require('../common/helper') +const logger = require('../common/logger') +const errors = require('../common/errors') +const models = require('../models') +const constants = require('../../app-constants') +const moment = require('moment') + +const WorkPeriod = models.WorkPeriod +const esClient = helper.getESClient() + +// "startDate" and "endDate" should always represent one week: +// "startDate" should be always Monday and "endDate" should be always Sunday of the same week. +// It should not include time or timezone, only date. +Joi.workPeriodStartDate = () => Joi.date().format('YYYY-MM-DD').custom((value, helpers) => { + const date = new Date(value) + const weekDay = date.getDay() + if (weekDay !== 0) { + return helpers.message('startDate should be always Sunday') + } + return value +}) +Joi.workPeriodEndDate = () => Joi.date() + .when('startDate', { + is: Joi.exist(), + then: Joi.date().format('YYYY-MM-DD').equal(Joi.ref('startDate', { + adjust: (value) => { + const date = new Date(value) + date.setDate(date.getDate() + 6) + return date + } + })).messages({ + 'any.only': 'endDate should be always the next Saturday' + }), + otherwise: Joi.date().format('YYYY-MM-DD').custom((value, helpers) => { + const date = new Date(value) + const weekDay = date.getDay() + if (weekDay !== 6) { + return helpers.message('endDate should be always Saturday') + } + return value + }).required() + }) +Joi.workPeriodEndDateOptional = () => Joi.date() + .when('startDate', { + is: Joi.exist(), + then: Joi.date().format('YYYY-MM-DD').equal(Joi.ref('startDate', { + adjust: (value) => { + const date = new Date(value) + date.setDate(date.getDate() + 6) + return date + } + })).messages({ + 'any.only': 'endDate should be always the next Saturday' + }), + otherwise: Joi.date().format('YYYY-MM-DD').custom((value, helpers) => { + const date = new Date(value) + const weekDay = date.getDay() + if (weekDay !== 6) { + return helpers.message('endDate should be always Saturday') + } + return value + }) + }) + +/** + * Check user scopes for getting payments + * @param {Object} currentUser the user who perform this operation. + * @returns {Boolean} true if user is machine and has read/all payment scopes + */ +function _checkUserScopesForGetPayments (currentUser) { + const getPaymentsScopes = [constants.Scopes.READ_WORK_PERIOD_PAYMENT, constants.Scopes.ALL_WORK_PERIOD_PAYMENT] + return currentUser.isMachine && helper.checkIfExists(getPaymentsScopes, currentUser.scopes) +} + +/** + * filter fields of work period by user role. + * @param {Object} currentUser the user who perform this operation. + * @param {Object} workPeriod the workPeriod with all fields + * @returns {Object} the workPeriod + */ +async function _getWorkPeriodFilteringFields (currentUser, workPeriod) { + if (currentUser.hasManagePermission || _checkUserScopesForGetPayments(currentUser)) { + return workPeriod + } + return _.omit(workPeriod, ['memberRate', 'payments']) +} + +/** + * Check user permission for getting work period. + * + * @param {Object} currentUser the user who perform this operation. + * @param {String} projectId the project id + * @returns {undefined} + */ +async function _checkUserPermissionForGetWorkPeriod (currentUser, projectId) { + if (!currentUser.hasManagePermission && !currentUser.isMachine && !currentUser.isConnectManager) { + await helper.checkIsMemberOfProject(currentUser.userId, projectId) + } +} + +/** + * Check user permission for creating or updating work period. + * + * @param {Object} currentUser the user who perform this operation. + * @returns {undefined} + */ +async function _checkUserPermissionForWriteWorkPeriod (currentUser) { + if (!currentUser.hasManagePermission && !currentUser.isMachine) { + throw new errors.ForbiddenError('You are not allowed to perform this action!') + } +} + +/** + * Checks if one of the date is missing and autocalculates it. + * @param {Object} data workPeriod data object + */ +function _autoCalculateDates (data) { + if (data.startDate && !data.endDate) { + const date = new Date(data.startDate) + date.setDate(date.getDate() + 6) + data.endDate = date + } else if (!data.startDate && data.endDate) { + const date = new Date(data.endDate) + date.setDate(date.getDate() - 6) + data.startDate = date + } +} + +/** + * Get workPeriod by id + * @param {Object} currentUser the user who perform this operation. + * @param {String} id the workPeriod id + * @param {Boolean} fromDb flag if query db for data or not + * @returns {Object} the workPeriod + */ +async function getWorkPeriod (currentUser, id, fromDb = false) { + if (!fromDb) { + try { + const workPeriod = await esClient.get({ + index: config.esConfig.ES_INDEX_WORK_PERIOD, + id + }) + + await _checkUserPermissionForGetWorkPeriod(currentUser, workPeriod.body._source.projectId) // check user permission + + const workPeriodRecord = { id: workPeriod.body._id, ...workPeriod.body._source } + return _getWorkPeriodFilteringFields(currentUser, workPeriodRecord) + } catch (err) { + if (helper.isDocumentMissingException(err)) { + throw new errors.NotFoundError(`id: ${id} "WorkPeriod" not found`) + } + if (err.httpStatus === HttpStatus.FORBIDDEN) { + throw err + } + logger.logFullError(err, { component: 'WorkPeriodService', context: 'getWorkPeriod' }) + } + } + logger.info({ component: 'WorkPeriodService', context: 'getWorkPeriod', message: 'try to query db for data' }) + const workPeriod = await WorkPeriod.findById(id, { withPayments: true }) + + await _checkUserPermissionForGetWorkPeriod(currentUser, workPeriod.projectId) // check user permission + // We should only return "memberRate" to Booking Manager, Administrator or M2M + return _getWorkPeriodFilteringFields(currentUser, workPeriod.dataValues) +} + +getWorkPeriod.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().guid().required(), + fromDb: Joi.boolean() +}).required() + +/** + * Create workPeriod + * @param {Object} currentUser the user who perform this operation + * @param {Object} workPeriod the workPeriod to be created + * @returns {Object} the created workPeriod + */ +async function createWorkPeriod (currentUser, workPeriod) { + // check permission + await _checkUserPermissionForWriteWorkPeriod(currentUser) + // If one of the dates are missing then auto-calculate it + _autoCalculateDates(workPeriod) + + const resourceBooking = await helper.ensureResourceBookingById(workPeriod.resourceBookingId) // ensure resource booking exists + workPeriod.projectId = resourceBooking.projectId + + const user = await helper.ensureUserById(resourceBooking.userId) // ensure user exists + workPeriod.userHandle = user.handle + + workPeriod.id = uuid.v4() + workPeriod.createdBy = await helper.getUserId(currentUser.userId) + + let created = null + try { + created = await WorkPeriod.create(workPeriod) + } catch (err) { + if (!_.isUndefined(err.original)) { + throw new errors.BadRequestError(err.original.detail) + } else { + throw err + } + } + + await helper.postEvent(config.TAAS_WORK_PERIOD_CREATE_TOPIC, created.toJSON()) + return created.dataValues +} + +createWorkPeriod.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + workPeriod: Joi.object().keys({ + resourceBookingId: Joi.string().uuid().required(), + startDate: Joi.workPeriodStartDate(), + endDate: Joi.workPeriodEndDate(), + daysWorked: Joi.number().integer().min(0).allow(null), + memberRate: Joi.number().allow(null), + customerRate: Joi.number().allow(null), + paymentStatus: Joi.paymentStatus().required() + }).required() +}).required() + +/** + * Update workPeriod + * @param {Object} currentUser the user who perform this operation + * @param {String} id the workPeriod id + * @param {Object} data the data to be updated + * @returns {Object} the updated workPeriod + */ +async function updateWorkPeriod (currentUser, id, data) { + // check permission + await _checkUserPermissionForWriteWorkPeriod(currentUser) + + const workPeriod = await WorkPeriod.findById(id) + const oldValue = workPeriod.toJSON() + + // if resourceBookingId is provided then update projectId and userHandle + if (data.resourceBookingId) { + const resourceBooking = await helper.ensureResourceBookingById(data.resourceBookingId) // ensure resource booking exists + data.projectId = resourceBooking.projectId + + const user = await helper.ensureUserById(resourceBooking.userId) // ensure user exists + data.userHandle = user.handle + } + // If one of the dates are missing then auto-calculate it + _autoCalculateDates(data) + + data.updatedBy = await helper.getUserId(currentUser.userId) + let updated = null + try { + updated = await workPeriod.update(data) + } catch (err) { + if (!_.isUndefined(err.original)) { + throw new errors.BadRequestError(err.original.detail) + } else { + throw err + } + } + + await helper.postEvent(config.TAAS_WORK_PERIOD_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue }) + return updated.dataValues +} + +/** + * Partially update workPeriod by id + * @param {Object} currentUser the user who perform this operation + * @param {String} id the workPeriod id + * @param {Object} data the data to be updated + * @returns {Object} the updated workPeriod + */ +async function partiallyUpdateWorkPeriod (currentUser, id, data) { + return updateWorkPeriod(currentUser, id, data) +} + +partiallyUpdateWorkPeriod.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().uuid().required(), + data: Joi.object().keys({ + resourceBookingId: Joi.string().uuid(), + startDate: Joi.workPeriodStartDate(), + endDate: Joi.workPeriodEndDateOptional(), + daysWorked: Joi.number().integer().min(0).allow(null), + memberRate: Joi.number().allow(null), + customerRate: Joi.number().allow(null), + paymentStatus: Joi.paymentStatus() + }).required() +}).required() + +/** + * Fully update workPeriod by id + * @param {Object} currentUser the user who perform this operation + * @param {String} id the workPeriod id + * @param {Object} data the data to be updated + * @returns {Object} the updated workPeriod + */ +async function fullyUpdateWorkPeriod (currentUser, id, data) { + return updateWorkPeriod(currentUser, id, data) +} + +fullyUpdateWorkPeriod.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().uuid().required(), + data: Joi.object().keys({ + resourceBookingId: Joi.string().uuid().required(), + startDate: Joi.workPeriodStartDate(), + endDate: Joi.workPeriodEndDate(), + daysWorked: Joi.number().integer().min(0).allow(null).default(null), + memberRate: Joi.number().allow(null).default(null), + customerRate: Joi.number().allow(null).default(null), + paymentStatus: Joi.paymentStatus().required() + }).required() +}).required() + +/** + * Delete workPeriod by id + * @params {Object} currentUser the user who perform this operation + * @params {String} id the workPeriod id + */ +async function deleteWorkPeriod (currentUser, id) { + // check permission + if (!currentUser.hasManagePermission && !currentUser.isMachine) { + throw new errors.ForbiddenError('You are not allowed to perform this action!') + } + + const workPeriod = await WorkPeriod.findById(id, { withPayments: true }) + if (_.includes(['completed', 'partially-completed'], workPeriod.paymentStatus)) { + throw new errors.BadRequestError("Can't delete WorkPeriod with paymentStatus completed or partially-completed") + } + await models.WorkPeriodPayment.destroy({ + where: { + workPeriodId: id + } + }) + await Promise.all(workPeriod.payments.map(({ id }) => helper.postEvent(config.TAAS_WORK_PERIOD_PAYMENT_DELETE_TOPIC, { id }))) + await workPeriod.destroy() + await helper.postEvent(config.TAAS_WORK_PERIOD_DELETE_TOPIC, { id }) +} + +deleteWorkPeriod.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + id: Joi.string().uuid().required() +}).required() + +/** + * List workPeriods + * @param {Object} currentUser the user who perform this operation. + * @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 searchWorkPeriods (currentUser, criteria, options = { returnAll: false }) { + // check user permission + if (!currentUser.hasManagePermission && !currentUser.isMachine && !currentUser.isConnectManager && !options.returnAll) { + if (!criteria.projectId) { // regular user can only search with filtering by "projectId" + throw new errors.ForbiddenError('Not allowed without filtering by "projectId"') + } + await helper.checkIsMemberOfProject(currentUser.userId, criteria.projectId) + } + + // `criteria.resourceBookingIds` could be array of ids, or comma separated string of ids + // in case it's comma separated string of ids we have to convert it to an array of ids + if ((typeof criteria.resourceBookingIds) === 'string') { + criteria.resourceBookingIds = criteria.resourceBookingIds.trim().split(',').map(resourceBookingIdRaw => { + const resourceBookingId = resourceBookingIdRaw.trim() + if (!uuid.validate(resourceBookingId)) { + throw new errors.BadRequestError(`resourceBookingId ${resourceBookingId} is not a valid uuid`) + } + return resourceBookingId + }) + } + const page = criteria.page + let perPage + if (options.returnAll) { + // To simplify the logic we are use a very large number for perPage + // because in practice there could hardly be so many records to be returned.(also consider we are using filters in the meantime) + // the number is limited by `index.max_result_window`, its default value is 10000, see + // https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-max-result-window + perPage = 10000 + } else { + perPage = criteria.perPage + } + + if (!criteria.sortBy) { + criteria.sortBy = 'id' + } + if (!criteria.sortOrder) { + criteria.sortOrder = 'desc' + } + try { + const sort = [{ [criteria.sortBy === 'id' ? '_id' : criteria.sortBy]: { order: criteria.sortOrder } }] + + const esQuery = { + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + body: { + query: { + bool: { + must: [] + } + }, + from: (page - 1) * perPage, + size: perPage, + sort + } + } + // change the date format to match with database model + if (criteria.startDate) { + criteria.startDate = moment(criteria.startDate).format('YYYY-MM-DD') + } + if (criteria.endDate) { + criteria.endDate = moment(criteria.endDate).format('YYYY-MM-DD') + } + _.each(_.pick(criteria, ['resourceBookingId', 'userHandle', 'projectId', 'startDate', 'endDate', 'paymentStatus']), (value, key) => { + esQuery.body.query.bool.must.push({ + term: { + [key]: { + value + } + } + }) + }) + // if criteria contains resourceBookingIds, filter resourceBookingId with this value + if (criteria.resourceBookingIds) { + esQuery.body.query.bool.filter = [{ + terms: { + resourceBookingId: criteria.resourceBookingIds + } + }] + } + logger.debug({ component: 'WorkPeriodService', context: 'searchWorkPeriods', message: `Query: ${JSON.stringify(esQuery)}` }) + + const { body } = await esClient.search(esQuery) + + return { + total: body.hits.total.value, + page, + perPage, + result: _.map(body.hits.hits, (hit) => { + const obj = _.cloneDeep(hit._source) + obj.id = hit._id + // We should only return "memberRate" to Booking Manager, Administrator or M2M + if (!currentUser.hasManagePermission && !_checkUserScopesForGetPayments(currentUser)) { + delete obj.memberRate + delete obj.payments + } + return obj + }) + } + } catch (err) { + logger.logFullError(err, { component: 'WorkPeriodService', context: 'searchWorkPeriods' }) + } + logger.info({ component: 'WorkPeriodService', context: 'searchWorkPeriods', message: 'fallback to DB query' }) + const filter = { [Op.and]: [] } + _.each(_.pick(criteria, ['resourceBookingId', 'userHandle', 'projectId', 'startDate', 'endDate', 'paymentStatus']), (value, key) => { + filter[Op.and].push({ [key]: value }) + }) + if (criteria.resourceBookingIds) { + filter[Op.and].push({ resourceBookingId: criteria.resourceBookingIds }) + } + const workPeriods = await WorkPeriod.findAll({ + where: filter, + include: [{ + model: models.WorkPeriodPayment, + as: 'payments', + required: false + }], + offset: ((page - 1) * perPage), + limit: perPage, + order: [[criteria.sortBy, criteria.sortOrder]] + }) + return { + fromDb: true, + total: workPeriods.length, + page, + perPage, + result: _.map(workPeriods, workPeriod => { + // We should only return "memberRate" to Booking Manager, Administrator or M2M + if (!currentUser.hasManagePermission && !_checkUserScopesForGetPayments(currentUser)) { + delete workPeriod.dataValues.memberRate + delete workPeriod.dataValues.payments + } + return workPeriod.dataValues + }) + } +} + +searchWorkPeriods.schema = Joi.object().keys({ + currentUser: Joi.object().required(), + criteria: Joi.object().keys({ + page: Joi.number().integer().min(1).default(1), + perPage: Joi.number().integer().min(1).max(10000).default(20), + sortBy: Joi.string().valid('id', 'resourceBookingId', 'userHandle', 'projectId', 'startDate', 'endDate', 'daysWorked', 'customerRate', 'memberRate', 'paymentStatus'), + sortOrder: Joi.string().valid('desc', 'asc'), + paymentStatus: Joi.paymentStatus(), + startDate: Joi.date().format('YYYY-MM-DD'), + endDate: Joi.date().format('YYYY-MM-DD'), + userHandle: Joi.string(), + projectId: Joi.number().integer(), + resourceBookingId: Joi.string().uuid(), + resourceBookingIds: Joi.alternatives( + Joi.string(), + Joi.array().items(Joi.string().uuid()) + ) + }).required(), + options: Joi.object() +}).required() + +module.exports = { + getWorkPeriod, + createWorkPeriod, + partiallyUpdateWorkPeriod, + fullyUpdateWorkPeriod, + deleteWorkPeriod, + searchWorkPeriods +} diff --git a/test/prepare.js b/test/prepare.js new file mode 100644 index 00000000..42277c70 --- /dev/null +++ b/test/prepare.js @@ -0,0 +1,7 @@ +/* + * Prepare for tests. + */ + +process.env.NODE_ENV = 'test' +require('../src/bootstrap') +require('../src/eventHandlers').init() 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..f557466e 100644 --- a/test/unit/ResourceBookingService.test.js +++ b/test/unit/ResourceBookingService.test.js @@ -1,379 +1,356 @@ /* eslint-disable no-unused-expressions */ -process.env.NODE_ENV = 'test' -require('../../src/bootstrap') -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 commonData = require('./common/CommonData') +const testData = require('./common/ResourceBookingData') const helper = require('../../src/common/helper') - -const esClient = helper.getESClient() const busApiClient = helper.getBusApiClient() - const ResourceBooking = models.ResourceBooking - +const WorkPeriod = models.WorkPeriod describe('resourceBooking service test', () => { - let isConnectMember - let userId - let stubIsConnectMember - let stubGetUserId 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 - }) - stubPostEvent = sinon.stub(busApiClient, 'postEvent').callsFake(async () => {}) + stubPostEvent = sinon.stub(busApiClient, 'postEvent').callsFake(async () => undefined) + stubCreateWorkPeriodService = sinon.stub(workPeriodService, 'createWorkPeriod').callsFake(async () => undefined) + stubUpdateWorkPeriodService = sinon.stub(workPeriodService, 'partiallyUpdateWorkPeriod').callsFake(async () => undefined) + stubDeleteWorkPeriodService = sinon.stub(workPeriodService, 'deleteWorkPeriod').callsFake(async () => undefined) }) afterEach(() => { sinon.restore() }) - describe('create resource booking test', () => { - it('create resource booking with booking manager success ', async () => { + describe('Create resource booking successfully', () => { + let stubEnsureJobById + let stubEnsureUserById + beforeEach(() => { + stubEnsureJobById = sinon.stub(helper, 'ensureJobById').callsFake(async () => undefined) + stubEnsureUserById = sinon.stub(helper, 'ensureUserById').callsFake(async () => commonData.UserTCConnCopilot) + }) + it('T01:Create resource booking start Saturday end Sunday', async () => { + const data = testData.T01 const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(() => { - return resourceBookingResponseBody + return data.resourceBooking.response }) - const entity = await service.createResourceBooking(bookingManagerUser, resourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingResponseBody.dataValues) + const entity = await service.createResourceBooking(commonData.currentUser, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.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(stubCreateWorkPeriodService.callCount).to.eq(6) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) + expect(stubCreateWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[0]) + expect(stubCreateWorkPeriodService.getCall(1).args[1]).to.deep.eq(data.workPeriod.request[1]) + expect(stubCreateWorkPeriodService.getCall(2).args[1]).to.deep.eq(data.workPeriod.request[2]) + expect(stubCreateWorkPeriodService.getCall(3).args[1]).to.deep.eq(data.workPeriod.request[3]) + expect(stubCreateWorkPeriodService.getCall(4).args[1]).to.deep.eq(data.workPeriod.request[4]) }) - - it('create resource booking with connect user success ', async () => { - const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(() => { - return resourceBookingResponseBody + it('T02:Create resource booking start Sunday end Saturday', async () => { + const data = testData.T02 + const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(async () => { + return data.resourceBooking.response }) - - const entity = await service.createResourceBooking(connectUser, resourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingResponseBody.dataValues) + const entity = await service.createResourceBooking(commonData.currentUser, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.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!') - } + 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(data.workPeriod.request[0]) }) - }) - - 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']) - } - } + it('T03:Create resource booking without startDate', async () => { + const data = testData.T03 + const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(async () => { + return data.resourceBooking.response }) - const entity = await service.getResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stub.calledOnce).to.be.true + const entity = await service.createResourceBooking(commonData.currentUser, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.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(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) }) - - 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']) - } - } + it('T04:Create resource booking without endDate', async () => { + const data = testData.T04 + const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(async () => { + return data.resourceBooking.response }) - - 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 + const entity = await service.createResourceBooking(commonData.currentUser, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.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(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) }) - - 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 + }) + describe('Create resource booking unsuccessfully', () => { + let stubEnsureJobById + let stubEnsureUserById + beforeEach(() => { + stubEnsureJobById = sinon.stub(helper, 'ensureJobById').callsFake(async () => undefined) + stubEnsureUserById = sinon.stub(helper, 'ensureUserById').callsFake(async () => commonData.UserTCConnCopilot) }) - - 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 + it('T05:Fail to create resource booking with startDate greater then endDate', async () => { + const data = testData.T05 + const stubDBCreate = sinon.stub(ResourceBooking, 'create').callsFake(() => { + return data.resourceBooking.response }) + let error 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 + await service.createResourceBooking(commonData.currentUser, data.resourceBooking.request) + } catch (err) { + error = err } + expect(error.message).to.eq(data.error.message) + expect(stubEnsureJobById.notCalled).to.be.true + expect(stubEnsureUserById.notCalled).to.be.true + expect(stubDBCreate.notCalled).to.be.true + expect(stubPostEvent.notCalled).to.be.true + expect(stubCreateWorkPeriodService.callCount).to.eq(0) + expect(stubUpdateWorkPeriodService.callCount).to.eq(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(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 + }) + describe('Update resource booking successfully', () => { + it('T06:Update resource booking dates and do not cause work period change', async () => { + const data = testData.T06 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - 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 data.workPeriod.response }) - - 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 + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.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(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(0) }) - - 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 + it('T07:Update resource booking dates and cause work period creation - 1', async () => { + const data = testData.T07 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - 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 + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response }) - 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 - } + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).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(data.workPeriod.request[0]) }) - }) - - 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 } - } + it('T08:Update resource booking dates and cause work period creation - 2', async () => { + const data = testData.T08 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - const entity = await service.fullyUpdateResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id, fullyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response + }) + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true + expect(stubWorkPeriodFindAll.called).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(data.workPeriod.request[0]) }) - - 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 } - } + it('T09:Update resource booking startDate and cause work period to be deleted', async () => { + const data = testData.T09 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - - const entity = await service.fullyUpdateResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id, fullyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response + }) + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.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(1) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[0]) }) - - 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 } - } + it('T10:Update resource booking endDate and cause work period to be deleted', async () => { + const data = testData.T10 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - 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 stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response }) - const entity = await service.partiallyUpdateResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id, partiallyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.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(0) + expect(stubDeleteWorkPeriodService.callCount).to.eq(1) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[0]) }) - - 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 } - } + it('T11:Update resource booking dates and cause work period daysWorked to change', async () => { + const data = testData.T11 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - - const entity = await service.partiallyUpdateResourceBooking(connectUser, resourceBookingResponseBody.dataValues.id, partiallyUpdateResourceBookingRequestBody) - expect(entity).to.deep.eql(resourceBookingRes.dataValues) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response + }) + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.calledOnce).to.be.true - expect(stubIsConnectMember.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[1]).to.deep.eq(data.workPeriod.request[0]) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(data.workPeriod.request[1]) }) - - 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 } - } + it('T12:Update resource booking dates and cause delete, update, create work period operations', async () => { + const data = testData.T12 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - 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!') - } - 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 } - } + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response }) - await service.deleteResourceBooking(bookingManagerUser, resourceBookingResponseBody.dataValues.id) - expect(stubResourceBookingFindOne.calledOnce).to.be.true + const entity = await service.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + expect(entity).to.deep.eql(data.resourceBooking.response.toJSON()) + expect(stubResourceBookingFindById.calledOnce).to.be.true expect(stubPostEvent.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(1) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[0]) + expect(stubUpdateWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[1]) + expect(stubUpdateWorkPeriodService.getCall(0).args[2]).to.deep.eq(data.workPeriod.request[2]) + expect(stubCreateWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[3]) }) - - it('delete resource booking test with connect user failed', async () => { + }) + describe('Update resource booking unsuccessfully', () => { + it('T13:Fail to update resource booking status to cancelled', async () => { + const data = testData.T13 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response + }) + let error 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(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + } catch (err) { + error = err } + expect(error.httpStatus).to.eq(data.error.httpStatus) + expect(error.message).to.eq(data.error.message) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.notCalled).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(0) }) - - it('delete resource booking test with topcoder user failed', async () => { + it('T14:Fail to update resource booking dates', async () => { + const data = testData.T14 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value + }) + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response + }) + let error 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.partiallyUpdateResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id, data.resourceBooking.request) + } catch (err) { + error = err } + expect(error.httpStatus).to.eq(data.error.httpStatus) + expect(error.message).to.eq(data.error.message) + expect(stubResourceBookingFindById.calledOnce).to.be.true + expect(stubPostEvent.notCalled).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(0) }) }) - - 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']) - }] - } - } - } + describe('Delete resource booking successfully', () => { + it('T15:Delete resource booking and cause work periods to be deleted ', async () => { + const data = testData.T15 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - 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 stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response }) - const entity = await service.searchResourceBookings({}) - expect(entity.result[0]).to.deep.eql(resourceBookingResponseBody.dataValues) - expect(stub.calledOnce).to.be.true + await service.deleteResourceBooking(commonData.currentUser, data.resourceBooking.value.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(2) + expect(stubDeleteWorkPeriodService.getCall(0).args[1]).to.deep.eq(data.workPeriod.request[0]) + expect(stubDeleteWorkPeriodService.getCall(1).args[1]).to.deep.eq(data.workPeriod.request[1]) }) - - it('search resource booking success when es search fails', async () => { - const stubESSearch = sinon.stub(esClient, 'search').callsFake(() => { - throw new Error('dedicated es failure') + }) + describe('Delete resource booking unsuccessfully', () => { + it('T16:Fail to delete resource booking with paid work periods', async () => { + const data = testData.T16 + const stubResourceBookingFindById = sinon.stub(ResourceBooking, 'findById').callsFake(async () => { + return data.resourceBooking.value }) - - const stubDBSearch = sinon.stub(ResourceBooking, 'findAll').callsFake(() => { - return [resourceBookingResponseBody] + const stubWorkPeriodFindAll = sinon.stub(WorkPeriod, 'findAll').callsFake(async () => { + return data.workPeriod.response }) - 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 + let error + try { + await service.deleteResourceBooking(commonData.currentUser, data.resourceBooking.value.dataValues.id) + } catch (err) { + error = err + } + expect(error.httpStatus).to.eq(data.error.httpStatus) + expect(error.message).to.eq(data.error.message) + expect(stubResourceBookingFindById.notCalled).to.be.true + expect(stubPostEvent.notCalled).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(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/WorkPeriodPaymentService.test.js b/test/unit/WorkPeriodPaymentService.test.js new file mode 100644 index 00000000..5e90b072 --- /dev/null +++ b/test/unit/WorkPeriodPaymentService.test.js @@ -0,0 +1,82 @@ +/* eslint-disable no-unused-expressions */ + +// const _ = require('lodash') +const expect = require('chai').expect +const sinon = require('sinon') +const models = require('../../src/models') +const service = require('../../src/services/WorkPeriodPaymentService') +const paymentService = require('../../src/services/PaymentService') +const commonData = require('./common/CommonData') +const testData = require('./common/WorkPeriodPaymentData') +const helper = require('../../src/common/helper') +// const esClient = helper.getESClient() +const busApiClient = helper.getBusApiClient() +describe('workPeriod service test', () => { + beforeEach(() => { + sinon.stub(busApiClient, 'postEvent').callsFake(async () => {}) + }) + + afterEach(() => { + sinon.restore() + }) + + describe('create work period test', () => { + let stubGetUserId + let stubEnsureWorkPeriodById + let stubEnsureResourceBookingById + let stubCreateWorkPeriodPayment + let stubCreatePayment + + beforeEach(async () => { + stubGetUserId = sinon.stub(helper, 'getUserId').callsFake(async () => testData.workPeriodPayment01.getUserIdResponse) + stubEnsureWorkPeriodById = sinon.stub(helper, 'ensureWorkPeriodById').callsFake(async () => testData.workPeriodPayment01.ensureWorkPeriodByIdResponse) + stubEnsureResourceBookingById = sinon.stub(helper, 'ensureResourceBookingById').callsFake(async () => testData.workPeriodPayment01.ensureResourceBookingByIdResponse) + stubCreateWorkPeriodPayment = sinon.stub(models.WorkPeriodPayment, 'create').callsFake(() => testData.workPeriodPayment01.response) + stubCreatePayment = sinon.stub(paymentService, 'createPayment').callsFake(async () => testData.workPeriodPayment01.createPaymentResponse) + }) + + it('create work period success', async () => { + const response = await service.createWorkPeriodPayment(commonData.currentUser, testData.workPeriodPayment01.request, { paymentProcessingSwitch: 'ON' }) + expect(stubGetUserId.calledOnce).to.be.true + expect(stubEnsureWorkPeriodById.calledOnce).to.be.true + expect(stubEnsureResourceBookingById.calledOnce).to.be.true + expect(stubCreatePayment.calledOnce).to.be.true + expect(stubCreateWorkPeriodPayment.calledOnce).to.be.true + expect(response).to.eql(testData.workPeriodPayment01.response.dataValues) + }) + + it('create work period success - billingAccountId is set', async () => { + await service.createWorkPeriodPayment(commonData.currentUser, testData.workPeriodPayment01.request, { paymentProcessingSwitch: 'ON' }) + expect(stubCreatePayment.calledOnce).to.be.true + expect(stubCreatePayment.args[0][0]).to.include({ + billingAccountId: testData.workPeriodPayment01.ensureResourceBookingByIdResponse.billingAccountId + }) + expect(stubCreateWorkPeriodPayment.calledOnce).to.be.true + expect(stubCreateWorkPeriodPayment.args[0][0]).to.include({ + billingAccountId: testData.workPeriodPayment01.ensureResourceBookingByIdResponse.billingAccountId + }) + }) + + it('fail to create work period if corresponding resource booking does not have bill account', async () => { + stubEnsureResourceBookingById.restore() + sinon.stub(helper, 'ensureResourceBookingById').callsFake(async () => testData.workPeriodPayment01.ensureResourceBookingByIdResponse02) + + try { + await service.createWorkPeriodPayment(commonData.currentUser, testData.workPeriodPayment01.request) + } catch (err) { + expect(err.message).to.include('"ResourceBooking" Billing account is not assigned to the resource booking') + } + }) + + describe('when PAYMENT_PROCESSING_SWITCH is ON/OFF', async () => { + it('do not create payment if PAYMENT_PROCESSING_SWITCH is OFF', async () => { + await service.createWorkPeriodPayment(commonData.currentUser, testData.workPeriodPayment01.request, { paymentProcessingSwitch: 'OFF' }) + expect(stubCreatePayment.calledOnce).to.be.false + }) + it('create payment if PAYMENT_PROCESSING_SWITCH is ON', async () => { + await service.createWorkPeriodPayment(commonData.currentUser, testData.workPeriodPayment01.request, { paymentProcessingSwitch: 'ON' }) + expect(stubCreatePayment.calledOnce).to.be.true + }) + }) + }) +}) diff --git a/test/unit/common/CommonData.js b/test/unit/common/CommonData.js new file mode 100644 index 00000000..08f8aa66 --- /dev/null +++ b/test/unit/common/CommonData.js @@ -0,0 +1,12 @@ +const currentUser = { + userId: '00000000-0000-0000-0000-000000000000', + isMachine: true +} +const UserTCConnCopilot = { + userId: '4709473d-f060-4102-87f8-4d51ff0b34c1', + handle: 'TCConnCopilot' +} +module.exports = { + currentUser, + UserTCConnCopilot +} diff --git a/test/unit/common/ResourceBookingData.js b/test/unit/common/ResourceBookingData.js new file mode 100644 index 00000000..4679a835 --- /dev/null +++ b/test/unit/common/ResourceBookingData.js @@ -0,0 +1,1004 @@ +const T01 = { + resourceBooking: { + request: { + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', + startDate: '2021-04-03', + endDate: '2021-05-02', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + billingAccountId: 68800079 + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-03', + endDate: '2021-05-02', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + request: [{ + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-03-28', + endDate: '2021-04-03', + daysWorked: null, + paymentStatus: 'pending' + }, + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-04', + endDate: '2021-04-10', + daysWorked: null, + paymentStatus: 'pending' + }, + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + paymentStatus: 'pending' + }, + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-18', + endDate: '2021-04-24', + daysWorked: null, + paymentStatus: 'pending' + }, + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-25', + endDate: '2021-05-01', + daysWorked: null, + paymentStatus: 'pending' + }, + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-05-02', + endDate: '2021-05-08', + daysWorked: null, + paymentStatus: 'pending' + }] + } +} +T01.resourceBooking.response.toJSON = () => T01.resourceBooking.response.dataValues +const T02 = { + resourceBooking: { + request: { + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', + startDate: '2021-04-11', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + billingAccountId: 68800079 + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-11', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + request: [{ + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + paymentStatus: 'pending' + }] + } +} +T02.resourceBooking.response.toJSON = () => T02.resourceBooking.response.dataValues +const T03 = { + resourceBooking: { + request: { + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + billingAccountId: 68800079 + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: null, + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + } +} +T03.resourceBooking.response.toJSON = () => T03.resourceBooking.response.dataValues +const T04 = { + resourceBooking: { + request: { + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', + startDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + billingAccountId: 68800079 + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-17', + endDate: null, + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + } +} +T04.resourceBooking.response.toJSON = () => T04.resourceBooking.response.dataValues +const T05 = { + resourceBooking: { + request: { + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '36762910-4efa-4db4-9b2a-c9ab54c232ed', + startDate: '2021-04-17', + endDate: '2021-04-16', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + billingAccountId: 68800079 + } + }, + error: { + message: 'endDate cannot be earlier than startDate' + } +} +const T06 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-11', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-13', + endDate: '2021-04-15' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-13', + endDate: '2021-04-15', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + 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' + }] + } +} +T06.resourceBooking.value.toJSON = () => T06.resourceBooking.value.dataValues +T06.resourceBooking.value.update = () => T06.resourceBooking.response +T06.resourceBooking.response.toJSON = () => T06.resourceBooking.response.dataValues +const T07 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-11', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-10', + endDate: '2021-04-15' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-10', + endDate: '2021-04-15', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + 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' + }], + request: [ + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-04', + endDate: '2021-04-10', + daysWorked: null, + paymentStatus: 'pending' + } + ] + } +} +T07.resourceBooking.value.toJSON = () => T07.resourceBooking.value.dataValues +T07.resourceBooking.value.update = () => T07.resourceBooking.response +T07.resourceBooking.response.toJSON = () => T07.resourceBooking.response.dataValues +const T08 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-11', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-12', + endDate: '2021-04-18' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-12', + endDate: '2021-04-18', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + 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' + }], + request: [ + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-18', + endDate: '2021-04-24', + daysWorked: null, + paymentStatus: 'pending' + } + ] + } +} +T08.resourceBooking.value.toJSON = () => T08.resourceBooking.value.dataValues +T08.resourceBooking.value.update = () => T08.resourceBooking.response +T08.resourceBooking.response.toJSON = () => T08.resourceBooking.response.dataValues +const T09 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-10', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-11', + endDate: '2021-04-15' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-11', + endDate: '2021-04-15', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + daysWorked: null, + 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: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + 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' + }], + request: [ + '10faf505-d0e3-4d13-a817-7f1319625e90' + ] + } +} +T09.resourceBooking.value.toJSON = () => T09.resourceBooking.value.dataValues +T09.resourceBooking.value.update = () => T09.resourceBooking.response +T09.resourceBooking.response.toJSON = () => T09.resourceBooking.response.dataValues +const T10 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-10', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-08', + endDate: '2021-04-10' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-08', + endDate: '2021-04-10', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + daysWorked: null, + 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: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: null, + 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' + }], + request: [ + '10faf505-d0e3-4d13-a817-7f1319625e91' + ] + } +} +T10.resourceBooking.value.toJSON = () => T10.resourceBooking.value.dataValues +T10.resourceBooking.value.update = () => T10.resourceBooking.response +T10.resourceBooking.response.toJSON = () => T10.resourceBooking.response.dataValues +const T11 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-10', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-08', + endDate: '2021-04-13' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-08', + endDate: '2021-04-13', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + daysWorked: 0, + 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: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: 3, + 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' + }], + request: [ + '10faf505-d0e3-4d13-a817-7f1319625e91', + { daysWorked: 2 } + ] + } +} +T11.resourceBooking.value.toJSON = () => T11.resourceBooking.value.dataValues +T11.resourceBooking.value.update = () => T11.resourceBooking.response +T11.resourceBooking.response.toJSON = () => T11.resourceBooking.response.dataValues +const T12 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-05', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-14', + endDate: '2021-04-24' + }, + response: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-14', + endDate: '2021-04-24', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + 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' + }, { + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: 4, + 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' + }], + request: [ + '10faf505-d0e3-4d13-a817-7f1319625e90', + '10faf505-d0e3-4d13-a817-7f1319625e91', + { daysWorked: 3 }, + { + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + startDate: '2021-04-18', + endDate: '2021-04-24', + daysWorked: null, + paymentStatus: 'pending' + } + ] + } +} +T12.resourceBooking.value.toJSON = () => T12.resourceBooking.value.dataValues +T12.resourceBooking.value.update = () => T12.resourceBooking.response +T12.resourceBooking.response.toJSON = () => T12.resourceBooking.response.dataValues +const T13 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-05', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + status: 'cancelled' + } + }, + error: { + httpStatus: 400, + message: `WorkPeriods with id of 10faf505-d0e3-4d13-a817-7f1319625e91 + has completed or partially-completed payment status.` + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + 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' + }, { + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: 4, + 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' + }] + } +} +T13.resourceBooking.value.toJSON = () => T13.resourceBooking.value.dataValues +const T14 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-05', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + }, + request: { + startDate: '2021-04-05', + endDate: '2021-04-10' + } + }, + error: { + httpStatus: 400, + message: `WorkPeriods with id of 10faf505-d0e3-4d13-a817-7f1319625e91 + has completed or partially-completed payment status.` + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + 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' + }, { + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: 4, + 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' + }] + } +} +T14.resourceBooking.value.toJSON = () => T14.resourceBooking.value.dataValues +const T15 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-05', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + 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' + }, { + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + 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' + }], + request: ['10faf505-d0e3-4d13-a817-7f1319625e90', '10faf505-d0e3-4d13-a817-7f1319625e91'] + } +} +T15.resourceBooking.value.toJSON = () => T15.resourceBooking.value.dataValues +T15.resourceBooking.value.destroy = () => undefined +const T16 = { + resourceBooking: { + value: { + dataValues: { + id: '520bb632-a02a-415e-9857-93b2ecbf7d60', + projectId: 21, + userId: 'a55fe1bc-1754-45fa-9adc-cf3d6d7c377a', + jobId: '6093e58c-683d-4022-8482-5515e8345016', + startDate: '2021-04-05', + endDate: '2021-04-17', + memberRate: 13.23, + customerRate: 13, + rateType: 'hourly', + createdAt: '2020-10-09T04:24:01.048Z', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + status: 'sourcing', + billingAccountId: 68800079 + } + } + }, + error: { + httpStatus: 400, + message: `WorkPeriods with id of 10faf505-d0e3-4d13-a817-7f1319625e91 + has completed or partially-completed payment status.` + }, + workPeriod: { + response: [{ + id: '10faf505-d0e3-4d13-a817-7f1319625e90', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-04', + endDate: '2021-04-10', + 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' + }, { + id: '10faf505-d0e3-4d13-a817-7f1319625e91', + resourceBookingId: '520bb632-a02a-415e-9857-93b2ecbf7d60', + userHandle: 'pshah_manager', + projectId: 21, + startDate: '2021-04-11', + endDate: '2021-04-17', + daysWorked: 4, + 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' + }] + } +} +T16.resourceBooking.value.toJSON = () => T16.resourceBooking.value.dataValues +module.exports = { + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16 +} diff --git a/test/unit/common/WorkPeriodPaymentData.js b/test/unit/common/WorkPeriodPaymentData.js new file mode 100644 index 00000000..d94d9280 --- /dev/null +++ b/test/unit/common/WorkPeriodPaymentData.js @@ -0,0 +1,41 @@ +const workPeriodPayment01 = { + request: { + workPeriodId: '467b4df7-ced4-41b9-9710-b83808cddaf4', + amount: 600, + status: 'completed' + }, + response: { + dataValues: { + workPeriodId: '467b4df7-ced4-41b9-9710-b83808cddaf4', + amount: 600, + status: 'completed', + id: '01971e6f-0f09-4a2a-bc2e-2adac0f00622', + challengeId: '00000000-0000-0000-0000-000000000000', + createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c', + updatedAt: '2021-04-21T12:58:07.535Z', + createdAt: '2021-04-21T12:58:07.535Z', + updatedBy: null + } + }, + getUserIdResponse: '79a39efd-91af-494a-b0f6-62310495effd', + ensureWorkPeriodByIdResponse: { + projectId: 111, + userHandle: 'pshah_manager', + endDate: '2021-03-13' + }, + ensureResourceBookingByIdResponse: { + billingAccountId: 68800079 + }, + ensureResourceBookingByIdResponse02: {}, + createPaymentResponse: { + id: 'c65f0cbf-b197-423d-91cc-db6e3bad9075' + } +} + +workPeriodPayment01.response.toJSON = function () { + return workPeriodPayment01.response +} + +module.exports = { + workPeriodPayment01 +} diff --git a/test/unit/common/testData.js b/test/unit/common/testData.js deleted file mode 100644 index dc607ba5..00000000 --- a/test/unit/common/testData.js +++ /dev/null @@ -1,789 +0,0 @@ - -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 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 jobResponseBody = { - dataValues: { - id: '36762910-4efa-4db4-9b2a-c9ab54c232ed', - 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', - startDate: '2020-09-27T04:17:23.131Z', - endDate: '2020-09-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' - }, - { - 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' - }, - { - id: '25f7b0e8-10a1-4bbc-b2f9-dacb1c72f1e9', - handle: 'Gaurav..Kumar', - firstName: 'Gaurav', - lastName: 'Kumar' - }, - { - id: '6fa6d708-68a6-47be-9591-4b5100921b3a', - handle: 'Kian.DuBuque', - firstName: 'Myles', - lastName: 'Connelly' - }, - { - id: '8edca7c4-0e71-4688-952a-42227f73ca32', - handle: 'BinoyVipin', - firstName: 'Binoy', - lastName: 'V' - }, - { - id: '247aaea8-f7e0-4ac8-b89e-4d78b76226b0', - handle: 'saikrupa87', - firstName: 'Miriyala', - lastName: 'Saikrupa reddy' - }, - { - id: 'cc7a694c-44a0-412b-9d1d-f98f7fe26a21', - handle: 'SriV_1672', - firstName: 'Srinivas', - lastName: 'Merugu' - }, - { - id: '07744775-eff1-443d-b56b-9d09ed02e599', - handle: 'Aachal', - firstName: 'Aachal ', - lastName: 'Jain' - }, - { - id: '0668fe37-b9cf-481b-8769-c3615833f80a', - handle: 'satadipa', - firstName: 'Satadipa', - lastName: 'Datta' - }, - { - 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' - }, - { - userId: 88773829, - handleLower: 'pe335869' - }, - { - userId: 8547899, - handleLower: 'tonyj', - photoURL: 'https://topcoder-dev-media.s3.amazonaws.com/member/profile/TonyJ-1604301092491.jpeg' - }, - { - 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' - }, - { - 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' - }, - { - 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' - }, - { - 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' - }, - { - 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' - }, - { - 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' - } - ] - }, - { - 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' - } - ] - }, - { - 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' - }, - { - 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' - } - ], - 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', - 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 - } - ], - 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, - 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' - } - ], - status: 'sourcing' - } - ] -} - -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 - } - ] -} - -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 -} 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') - }) - }) })