From 6d1b0df45ffefedb00616393a65a4ecd38ddbec0 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Wed, 31 Mar 2021 00:00:06 +0300 Subject: [PATCH 01/11] work period endpoint --- README.md | 4 + VERIFICATION.md | 12 +- config/default.js | 12 +- src/app.js | 7 +- src/bootstrap.js | 1 + src/scripts/createIndex.js | 23 ++++ src/scripts/deleteIndex.js | 3 +- src/scripts/view-data.js | 3 +- src/services/WorkPeriodProcessorService.js | 109 ++++++++++++++++++ .../taas.workperiod.create.event.json | 22 ++++ .../taas.workperiod.delete.event.json | 9 ++ .../taas.workperiod.update.event.json | 21 ++++ 12 files changed, 217 insertions(+), 9 deletions(-) create mode 100644 src/services/WorkPeriodProcessorService.js create mode 100644 test/messages/taas.workperiod.create.event.json create mode 100644 test/messages/taas.workperiod.delete.event.json create mode 100644 test/messages/taas.workperiod.update.event.json diff --git a/README.md b/README.md index 0501dec..d8409ab 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ The following parameters can be set in config files or in env variables: - `topics.TAAS_RESOURCE_BOOKING_CREATE_TOPIC`: the create resource booking entity Kafka message topic - `topics.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC`: the update resource booking entity Kafka message topic - `topics.TAAS_RESOURCE_BOOKING_DELETE_TOPIC`: the delete resource booking entity Kafka message topic +- `topics.TAAS_WORK_PERIOD_CREATE_TOPIC`: the create work period entity Kafka message topic +- `topics.TAAS_WORK_PERIOD_UPDATE_TOPIC`: the update work period entity Kafka message topic +- `topics.TAAS_WORK_PERIOD_DELETE_TOPIC`: the delete work period entity Kafka message topic - `esConfig.HOST`: Elasticsearch host - `esConfig.AWS_REGION`: The Amazon region to use when using AWS Elasticsearch service - `esConfig.ELASTICCLOUD.id`: The elastic cloud id, if your elasticsearch instance is hosted on elastic cloud. DO NOT provide a value for ES_HOST if you are using this @@ -38,6 +41,7 @@ The following parameters can be set in config files or in env variables: - `esConfig.ES_INDEX_JOB`: the index name for job - `esConfig.ES_INDEX_JOB_CANDIDATE`: the index name for job candidate - `esConfig.ES_INDEX_RESOURCE_BOOKING`: the index name for resource booking +- `esConfig.ES_INDEX_WORK_PERIOD`: the index name for work period - `auth0.AUTH0_URL`: Auth0 URL, used to get TC M2M token - `auth0.AUTH0_AUDIENCE`: Auth0 audience, used to get TC M2M token diff --git a/VERIFICATION.md b/VERIFICATION.md index d1d48d3..c6930b9 100644 --- a/VERIFICATION.md +++ b/VERIFICATION.md @@ -2,7 +2,7 @@ ## Create documents in ES -- Run the following commands to create `Job`, `JobCandidate` and `ResourceBooking` documents in ES. +- Run the following commands to create `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod` documents in ES. ``` bash # for Job @@ -11,12 +11,14 @@ docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.jobcandidate.create < test/messages/taas.jobcandidate.create.event.json # for ResourceBooking docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.resourcebooking.create < test/messages/taas.resourcebooking.create.event.json + # for WorkPeriod + docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiod.create < test/messages/taas.workperiod.create.event.json ``` - Run `npm run view-data ` to see if documents were created. ## Update documents in ES -- Run the following commands to update `Job`, `JobCandidate` and `ResourceBooking` documents in ES. +- Run the following commands to update `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod` documents in ES. ``` bash # for Job @@ -25,12 +27,14 @@ docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.jobcandidate.update < test/messages/taas.jobcandidate.update.event.json # for ResourceBooking docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.resourcebooking.update < test/messages/taas.resourcebooking.update.event.json + # for WorkPeriod + docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiod.update < test/messages/taas.workperiod.update.event.json ``` - Run `npm run view-data ` to see if documents were updated. ## Delete documents in ES -- Run the following commands to delete `Job`, `JobCandidate` and `ResourceBooking` documents in ES. +- Run the following commands to delete `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod` documents in ES. ``` bash # for Job @@ -39,6 +43,8 @@ docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.jobcandidate.delete < test/messages/taas.jobcandidate.delete.event.json # for ResourceBooking docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.resourcebooking.delete < test/messages/taas.resourcebooking.delete.event.json + # for WorkPeriod + docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiod.delete < test/messages/taas.workperiod.delete.event.json ``` - Run `npm run view-data ` to see if documents were deleted. diff --git a/config/default.js b/config/default.js index c09c3e5..446ab4e 100644 --- a/config/default.js +++ b/config/default.js @@ -16,6 +16,7 @@ module.exports = { KAFKA_GROUP_ID: process.env.KAFKA_GROUP_ID || 'taas-es-processor', topics: { + // topics for job service TAAS_JOB_CREATE_TOPIC: process.env.TAAS_JOB_CREATE_TOPIC || 'taas.job.create', TAAS_JOB_UPDATE_TOPIC: process.env.TAAS_JOB_UPDATE_TOPIC || 'taas.job.update', TAAS_JOB_DELETE_TOPIC: process.env.TAAS_JOB_DELETE_TOPIC || 'taas.job.delete', @@ -23,10 +24,14 @@ module.exports = { TAAS_JOB_CANDIDATE_CREATE_TOPIC: process.env.TAAS_JOB_CANDIDATE_CREATE_TOPIC || 'taas.jobcandidate.create', TAAS_JOB_CANDIDATE_UPDATE_TOPIC: process.env.TAAS_JOB_CANDIDATE_UPDATE_TOPIC || 'taas.jobcandidate.update', TAAS_JOB_CANDIDATE_DELETE_TOPIC: process.env.TAAS_JOB_CANDIDATE_DELETE_TOPIC || 'taas.jobcandidate.delete', - // topics for job service + // topics for resource booking service TAAS_RESOURCE_BOOKING_CREATE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_CREATE_TOPIC || 'taas.resourcebooking.create', TAAS_RESOURCE_BOOKING_UPDATE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC || 'taas.resourcebooking.update', - TAAS_RESOURCE_BOOKING_DELETE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_DELETE_TOPIC || 'taas.resourcebooking.delete' + TAAS_RESOURCE_BOOKING_DELETE_TOPIC: process.env.TAAS_RESOURCE_BOOKING_DELETE_TOPIC || 'taas.resourcebooking.delete', + // topics for work period service + TAAS_WORK_PERIOD_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_CREATE_TOPIC || 'taas.workperiod.create', + TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update', + TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete' }, esConfig: { @@ -42,7 +47,8 @@ module.exports = { ES_INDEX_JOB: process.env.ES_INDEX_JOB || 'job', ES_INDEX_JOB_CANDIDATE: process.env.ES_INDEX_JOB_CANDIDATE || 'job_candidate', - ES_INDEX_RESOURCE_BOOKING: process.env.ES_INDEX_RESOURCE_BOOKING || 'resource_booking' + ES_INDEX_RESOURCE_BOOKING: process.env.ES_INDEX_RESOURCE_BOOKING || 'resource_booking', + ES_INDEX_WORK_PERIOD: process.env.ES_INDEX_WORK_PERIOD || 'work_period' }, auth0: { diff --git a/src/app.js b/src/app.js index 7414dc2..1d3ae47 100644 --- a/src/app.js +++ b/src/app.js @@ -12,6 +12,7 @@ const helper = require('./common/helper') const JobProcessorService = require('./services/JobProcessorService') const JobCandidateProcessorService = require('./services/JobCandidateProcessorService') const ResourceBookingProcessorService = require('./services/ResourceBookingProcessorService') +const WorkPeriodProcessorService = require('./services/WorkPeriodProcessorService') const Mutex = require('async-mutex').Mutex const events = require('events') @@ -38,7 +39,11 @@ const topicServiceMapping = { // resource booking [config.topics.TAAS_RESOURCE_BOOKING_CREATE_TOPIC]: ResourceBookingProcessorService.processCreate, [config.topics.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC]: ResourceBookingProcessorService.processUpdate, - [config.topics.TAAS_RESOURCE_BOOKING_DELETE_TOPIC]: ResourceBookingProcessorService.processDelete + [config.topics.TAAS_RESOURCE_BOOKING_DELETE_TOPIC]: ResourceBookingProcessorService.processDelete, + // work period + [config.topics.TAAS_WORK_PERIOD_CREATE_TOPIC]: WorkPeriodProcessorService.processCreate, + [config.topics.TAAS_WORK_PERIOD_UPDATE_TOPIC]: WorkPeriodProcessorService.processUpdate, + [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete } // Start kafka consumer diff --git a/src/bootstrap.js b/src/bootstrap.js index 5648bbc..0f58277 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -9,6 +9,7 @@ Joi.jobStatus = () => Joi.string().valid('sourcing', 'in-review', 'assigned', 'c Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview') Joi.workload = () => Joi.string().valid('full-time', 'fractional') Joi.title = () => Joi.string().max(128) +Joi.paymentStatus = () => Joi.string().valid('pending', 'partially-completed', '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. diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index c6986df..095633e 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -75,6 +75,29 @@ async function createIndex () { } } } + }, + { + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + body: { + mappings: { + properties: { + 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' }, + createdAt: { type: 'date' }, + createdBy: { type: 'keyword' }, + updatedAt: { type: 'date' }, + updatedBy: { type: 'keyword' } + } + } + } }] for (const index of indices) { diff --git a/src/scripts/deleteIndex.js b/src/scripts/deleteIndex.js index 9c3a1bb..69594b4 100644 --- a/src/scripts/deleteIndex.js +++ b/src/scripts/deleteIndex.js @@ -11,7 +11,8 @@ async function deleteIndex () { const esClient = helper.getESClient() 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')] for (const index of indices) { await esClient.indices.delete({ index diff --git a/src/scripts/view-data.js b/src/scripts/view-data.js index 1db36d5..9c3d0ce 100644 --- a/src/scripts/view-data.js +++ b/src/scripts/view-data.js @@ -11,7 +11,8 @@ const esClient = helper.getESClient() const modelIndexMapping = { Job: 'ES_INDEX_JOB', JobCandidate: 'ES_INDEX_JOB_CANDIDATE', - ResourceBooking: 'ES_INDEX_RESOURCE_BOOKING' + ResourceBooking: 'ES_INDEX_RESOURCE_BOOKING', + WorkPeriod: 'ES_INDEX_WORK_PERIOD' } async function showESData () { diff --git a/src/services/WorkPeriodProcessorService.js b/src/services/WorkPeriodProcessorService.js new file mode 100644 index 0000000..568c746 --- /dev/null +++ b/src/services/WorkPeriodProcessorService.js @@ -0,0 +1,109 @@ +/** + * WorkPeriod Processor Service + */ + +const Joi = require('@hapi/joi') +const logger = require('../common/logger') +const helper = require('../common/helper') +const constants = require('../common/constants') +const config = require('config') + +const esClient = helper.getESClient() + +/** + * Process create entity message + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processCreate (message, transactionId) { + const workPeriod = message.payload + await esClient.createExtra({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: workPeriod.id, + transactionId, + body: workPeriod, + refresh: constants.esRefreshOption + }) +} + +processCreate.schema = { + message: Joi.object().keys({ + topic: Joi.string().required(), + originator: Joi.string().required(), + timestamp: Joi.date().required(), + 'mime-type': Joi.string().required(), + payload: Joi.object().keys({ + id: Joi.string().uuid().required(), + resourceBookingId: Joi.string().uuid().required(), + userHandle: Joi.string().required(), + projectId: Joi.number().integer().required(), + startDate: Joi.string().required(), + endDate: Joi.string().required(), + daysWorked: Joi.number().integer().min(0).allow(null), + memberRate: Joi.number().allow(null), + customerRate: Joi.number().allow(null), + paymentStatus: Joi.paymentStatus().required(), + createdAt: Joi.date().required(), + createdBy: Joi.string().uuid().required(), + updatedAt: Joi.date().allow(null), + updatedBy: Joi.string().uuid().allow(null) + }).required() + }).required(), + transactionId: Joi.string().required() +} + +/** + * Process update entity message + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processUpdate (message, transactionId) { + const data = message.payload + await esClient.updateExtra({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: data.id, + transactionId, + body: { + doc: data + }, + refresh: constants.esRefreshOption + }) +} + +processUpdate.schema = processCreate.schema + +/** + * Process delete entity message + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processDelete (message, transactionId) { + const id = message.payload.id + await esClient.deleteExtra({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id, + transactionId, + refresh: constants.esRefreshOption + }) +} + +processDelete.schema = { + message: Joi.object().keys({ + topic: Joi.string().required(), + originator: Joi.string().required(), + timestamp: Joi.date().required(), + 'mime-type': Joi.string().required(), + payload: Joi.object().keys({ + id: Joi.string().uuid().required() + }).required() + }).required(), + transactionId: Joi.string().required() +} + +module.exports = { + processCreate, + processUpdate, + processDelete +} + +logger.buildService(module.exports, 'WorkPeriodProcessorService') diff --git a/test/messages/taas.workperiod.create.event.json b/test/messages/taas.workperiod.create.event.json new file mode 100644 index 0000000..7afea61 --- /dev/null +++ b/test/messages/taas.workperiod.create.event.json @@ -0,0 +1,22 @@ +{ + "topic": "taas.workperiod.create", + "originator": "taas-api", + "timestamp": "2021-03-30T20:24:17.555Z", + "mime-type": "application/json", + "payload": { + "resourceBookingId": "6cf2edf6-4b2c-40ef-96db-e1ddb771fdd3", + "startDate": "2021-03-14", + "endDate": "2021-03-20", + "daysWorked": 3, + "memberRate": 13.13, + "customerRate": 13.13, + "paymentStatus": "cancelled", + "projectId": 111, + "userHandle": "pshah_manager", + "id": "926040c4-1709-4de2-b2b6-52adf6e5e72d", + "createdBy": "00000000-0000-0000-0000-000000000000", + "updatedAt": "2021-03-30T20:24:17.541Z", + "createdAt": "2021-03-30T20:24:17.541Z", + "updatedBy": null + } +} \ No newline at end of file diff --git a/test/messages/taas.workperiod.delete.event.json b/test/messages/taas.workperiod.delete.event.json new file mode 100644 index 0000000..3b3207c --- /dev/null +++ b/test/messages/taas.workperiod.delete.event.json @@ -0,0 +1,9 @@ +{ + "topic": "taas.workperiod.delete", + "originator": "taas-api", + "timestamp": "2021-03-30T20:13:58.491Z", + "mime-type": "application/json", + "payload": { + "id": "926040c4-1709-4de2-b2b6-52adf6e5e72d" + } +} \ No newline at end of file diff --git a/test/messages/taas.workperiod.update.event.json b/test/messages/taas.workperiod.update.event.json new file mode 100644 index 0000000..0e8ca71 --- /dev/null +++ b/test/messages/taas.workperiod.update.event.json @@ -0,0 +1,21 @@ +{ + "topic": "taas.workperiod.update", + "originator": "taas-api", + "timestamp": "2021-03-30T20:13:53.179Z", + "mime-type": "application/json", + "payload": { + "id": "926040c4-1709-4de2-b2b6-52adf6e5e72d", + "resourceBookingId": "79317ff6-5b30-45c2-ace8-b97282b042a8", + "startDate": "2021-03-14", + "endDate": "2021-03-20", + "daysWorked": 3, + "memberRate": 13.13, + "customerRate": 13.13, + "paymentStatus": "pending", + "projectId": 111, + "userHandle": "pshah_manager", + "createdBy": "00000000-0000-0000-0000-000000000000", + "createdAt": "2021-03-30T20:13:34.670Z", + "updatedAt": "2021-03-30T20:13:45.354Z" + } +} \ No newline at end of file From 9a425979347fbc017462688eb7856b05d433c749 Mon Sep 17 00:00:00 2001 From: narekcat Date: Sat, 10 Apr 2021 01:32:15 +0400 Subject: [PATCH 02/11] Add work period payments. --- README.md | 2 + VERIFICATION.md | 8 +- config/default.js | 5 +- local/docker-compose.yml | 2 +- src/app.js | 6 +- src/bootstrap.js | 1 + src/scripts/createIndex.js | 13 ++ .../WorkPeriodPaymentProcessorService.js | 134 ++++++++++++++++++ .../taas.workperiodpayment.create.event.json | 1 + .../taas.workperiodpayment.update.event.json | 1 + 10 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 src/services/WorkPeriodPaymentProcessorService.js create mode 100644 test/messages/taas.workperiodpayment.create.event.json create mode 100644 test/messages/taas.workperiodpayment.update.event.json diff --git a/README.md b/README.md index d8409ab..045684f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ The following parameters can be set in config files or in env variables: - `topics.TAAS_WORK_PERIOD_CREATE_TOPIC`: the create work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_UPDATE_TOPIC`: the update work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_DELETE_TOPIC`: the delete work period entity Kafka message topic +- `topics.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC`: the create work period payment entity Kafka message topic +- `topics.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC`: the update work period payment entity Kafka message topic - `esConfig.HOST`: Elasticsearch host - `esConfig.AWS_REGION`: The Amazon region to use when using AWS Elasticsearch service - `esConfig.ELASTICCLOUD.id`: The elastic cloud id, if your elasticsearch instance is hosted on elastic cloud. DO NOT provide a value for ES_HOST if you are using this diff --git a/VERIFICATION.md b/VERIFICATION.md index c6930b9..5410bcf 100644 --- a/VERIFICATION.md +++ b/VERIFICATION.md @@ -2,7 +2,7 @@ ## Create documents in ES -- Run the following commands to create `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod` documents in ES. +- Run the following commands to create `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod`, `WorkPeriodPayment` documents in ES. ``` bash # for Job @@ -13,12 +13,14 @@ docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.resourcebooking.create < test/messages/taas.resourcebooking.create.event.json # for WorkPeriod docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiod.create < test/messages/taas.workperiod.create.event.json + # for WorkPeriodPayment + docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiodpayment.create < test/messages/taas.workperiodpayment.create.event.json ``` - Run `npm run view-data ` to see if documents were created. ## Update documents in ES -- Run the following commands to update `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod` documents in ES. +- Run the following commands to update `Job`, `JobCandidate`, `ResourceBooking`, `WorkPeriod`, `WorkPeriodPayment` documents in ES. ``` bash # for Job @@ -29,6 +31,8 @@ docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.resourcebooking.update < test/messages/taas.resourcebooking.update.event.json # for WorkPeriod docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiod.update < test/messages/taas.workperiod.update.event.json + # for WorkPeriodPayment + docker exec -i taas-es-processor_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic taas.workperiodpayment.update < test/messages/taas.workperiodpayment.update.event.json ``` - Run `npm run view-data ` to see if documents were updated. diff --git a/config/default.js b/config/default.js index 446ab4e..7a8dbf8 100644 --- a/config/default.js +++ b/config/default.js @@ -31,7 +31,10 @@ module.exports = { // topics for work period service TAAS_WORK_PERIOD_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_CREATE_TOPIC || 'taas.workperiod.create', TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update', - TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete' + TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete', + // topics for work period payment service + TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC || 'taas.workperiodpayment.create', + TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC || 'taas.workperiodpayment.update' }, esConfig: { diff --git a/local/docker-compose.yml b/local/docker-compose.yml index 5d2d803..35e9486 100644 --- a/local/docker-compose.yml +++ b/local/docker-compose.yml @@ -12,7 +12,7 @@ services: - "9092:9092" environment: KAFKA_ADVERTISED_HOST_NAME: localhost - KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1" + KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.workperiod.create:1:1,taas.workperiodpayment.create:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.workperiod.update:1:1,taas.workperiodpayment.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1,taas.workperiod.delete:1:1" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 esearch: image: elasticsearch:7.7.1 diff --git a/src/app.js b/src/app.js index 1d3ae47..c38c03d 100644 --- a/src/app.js +++ b/src/app.js @@ -13,6 +13,7 @@ const JobProcessorService = require('./services/JobProcessorService') const JobCandidateProcessorService = require('./services/JobCandidateProcessorService') const ResourceBookingProcessorService = require('./services/ResourceBookingProcessorService') const WorkPeriodProcessorService = require('./services/WorkPeriodProcessorService') +const WorkPeriodPaymentProcessorService = require('./services/WorkPeriodPaymentProcessorService') const Mutex = require('async-mutex').Mutex const events = require('events') @@ -43,7 +44,10 @@ const topicServiceMapping = { // work period [config.topics.TAAS_WORK_PERIOD_CREATE_TOPIC]: WorkPeriodProcessorService.processCreate, [config.topics.TAAS_WORK_PERIOD_UPDATE_TOPIC]: WorkPeriodProcessorService.processUpdate, - [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete + [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete, + // work period payment + [config.topics.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC]: WorkPeriodPaymentProcessorService.processCreate, + [config.topics.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC]: WorkPeriodPaymentProcessorService.processUpdate } // Start kafka consumer diff --git a/src/bootstrap.js b/src/bootstrap.js index 0f58277..6c9c001 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -10,6 +10,7 @@ Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist Joi.workload = () => Joi.string().valid('full-time', 'fractional') 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. diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index 095633e..fad96d3 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -91,6 +91,19 @@ async function createIndex () { memberRate: { type: 'float' }, customerRate: { type: 'float' }, paymentStatus: { type: 'keyword' }, + payments: { + type: 'nested', + properties: { + workPeriodId: { type: 'keyword' }, + challengeId: { type: 'keyword' }, + amount: { type: 'float' }, + status: { type: 'keyword' }, + createdAt: { type: 'date' }, + createdBy: { type: 'keyword' }, + updatedAt: { type: 'date' }, + updatedBy: { type: 'keyword' } + } + }, createdAt: { type: 'date' }, createdBy: { type: 'keyword' }, updatedAt: { type: 'date' }, diff --git a/src/services/WorkPeriodPaymentProcessorService.js b/src/services/WorkPeriodPaymentProcessorService.js new file mode 100644 index 0000000..45fd6c5 --- /dev/null +++ b/src/services/WorkPeriodPaymentProcessorService.js @@ -0,0 +1,134 @@ +/** + * WorkPeriodPayment Processor Service + */ + +const Joi = require('@hapi/joi') +const config = require('config') +const _ = require('lodash') +const logger = require('../common/logger') +const helper = require('../common/helper') +const constants = require('../common/constants') + +const esClient = helper.getESClient() + +/** + * Process create entity message + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processCreate (message, transactionId) { + const data = message.payload + const workPeriod = await esClient.get({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: data.workPeriodId + }) + const payments = _.isArray(workPeriod.body._source.payments) ? workPeriod.body._source.payments : [] + payments.push(data) + + return esClient.update({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: data.workPeriodId, + transactionId, + body: { + doc: _.assign(workPeriod.body._source, { payments }) + }, + refresh: constants.esRefreshOption + }) +} + +processCreate.schema = { + message: Joi.object().keys({ + topic: Joi.string().required(), + originator: Joi.string().required(), + timestamp: Joi.date().required(), + 'mime-type': Joi.string().required(), + payload: Joi.object().keys({ + id: Joi.string().uuid().required(), + workPeriodId: Joi.string().uuid().required(), + challengeId: Joi.string().uuid().required(), + amount: Joi.number().greater(0).allow(null), + status: Joi.workPeriodPaymentStatus().required(), + createdAt: Joi.date().required(), + createdBy: Joi.string().uuid().required(), + updatedAt: Joi.date().allow(null), + updatedBy: Joi.string().uuid().allow(null) + }).required() + }).required(), + transactionId: Joi.string().required() +} + +/** + * Process update entity message + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processUpdate (message, transactionId) { + const data = message.payload + let workPeriod = await esClient.search({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + body: { + query: { + nested: { + path: 'payments', + query: { + match: { 'payments.id': data.id } + } + } + } + } + }) + let payments + // if WorkPeriodPayment's workPeriodId changed then it must be deleted from the old WorkPeriod + // and added to the new WorkPeriod + if (workPeriod.body.hits.hits[0]._source.id !== data.workPeriodId) { + payments = _.filter(workPeriod.body.hits.hits[0]._source.payments, (payment) => payment.id !== data.id) + await esClient.update({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: workPeriod.body.hits.hits[0]._source.id, + transactionId, + body: { + doc: _.assign(workPeriod.body.hits.hits[0]._source, { payments }) + } + }) + workPeriod = await esClient.get({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: data.workPeriodId + }) + payments = _.isArray(workPeriod.body._source.payments) ? workPeriod.body._source.payments : [] + payments.push(data) + return esClient.update({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: data.workPeriodId, + transactionId, + body: { + doc: _.assign(workPeriod.body._source, { payments }) + } + }) + } + + payments = _.map(workPeriod.body.hits.hits[0]._source.payments, (payment) => { + if (payment.id === data.id) { + return _.assign(payment, data) + } + return payment + }) + + return esClient.update({ + index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), + id: data.workPeriodId, + transactionId, + body: { + doc: _.assign(workPeriod.body.hits.hits[0]._source, { payments }) + }, + refresh: constants.esRefreshOption + }) +} + +processUpdate.schema = processCreate.schema + +module.exports = { + processCreate, + processUpdate +} + +logger.buildService(module.exports, 'WorkPeriodPaymentProcessorService') diff --git a/test/messages/taas.workperiodpayment.create.event.json b/test/messages/taas.workperiodpayment.create.event.json new file mode 100644 index 0000000..25ab9cc --- /dev/null +++ b/test/messages/taas.workperiodpayment.create.event.json @@ -0,0 +1 @@ +{"topic":"taas.workperiodpayment.create","originator":"taas-api","timestamp":"2021-04-09T20:10:33.770Z","mime-type":"application/json","payload":{"challengeId":"00000000-0000-0000-0000-000000000000","workPeriodId":"140b7407-540d-40c3-ad23-905d932aa9c8","amount":600,"status":"completed","id":"09c80ee6-21be-45a4-9c3c-7ec4c75ece79","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedAt":"2021-04-09T20:10:33.755Z","createdAt":"2021-04-09T20:10:33.755Z","updatedBy":null}} \ No newline at end of file diff --git a/test/messages/taas.workperiodpayment.update.event.json b/test/messages/taas.workperiodpayment.update.event.json new file mode 100644 index 0000000..66e5bce --- /dev/null +++ b/test/messages/taas.workperiodpayment.update.event.json @@ -0,0 +1 @@ +{"topic":"taas.workperiodpayment.update","originator":"taas-api","timestamp":"2021-04-09T20:12:26.994Z","mime-type":"application/json","payload":{"id":"09c80ee6-21be-45a4-9c3c-7ec4c75ece79","workPeriodId":"140b7407-540d-40c3-ad23-905d932aa9c8","challengeId":"00000000-0000-0000-0000-000000000000","amount":1600,"status":"completed","createdBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","updatedBy":"57646ff9-1cd3-4d3c-88ba-eb09a395366c","createdAt":"2021-04-09T20:10:33.755Z","updatedAt":"2021-04-09T20:12:26.966Z"}} \ No newline at end of file From 1012957996d5001cc6508fe4969a7e667943950d Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 15 Apr 2021 01:27:31 +0300 Subject: [PATCH 03/11] resource booking status fixed --- src/bootstrap.js | 1 + src/services/ResourceBookingProcessorService.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index 0f58277..922f29e 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -6,6 +6,7 @@ global.Promise = require('bluebird') 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.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist', 'rejected', 'cancelled', 'interview') Joi.workload = () => Joi.string().valid('full-time', 'fractional') Joi.title = () => Joi.string().max(128) diff --git a/src/services/ResourceBookingProcessorService.js b/src/services/ResourceBookingProcessorService.js index 964f4d0..4972afe 100644 --- a/src/services/ResourceBookingProcessorService.js +++ b/src/services/ResourceBookingProcessorService.js @@ -46,7 +46,7 @@ processCreate.schema = { createdBy: Joi.string().uuid().required(), updatedAt: Joi.date().allow(null), updatedBy: Joi.string().uuid().allow(null), - status: Joi.jobStatus().required() + status: Joi.resourceBookingStatus().required() }).required() }).required(), transactionId: Joi.string().required() From e965836c925a62735225c322f5f4effbd52316d9 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Sat, 17 Apr 2021 11:41:38 +0300 Subject: [PATCH 04/11] fix: unit test --- test/messages/taas.resourcebooking.create.event.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/messages/taas.resourcebooking.create.event.json b/test/messages/taas.resourcebooking.create.event.json index 1a358ba..92ec817 100644 --- a/test/messages/taas.resourcebooking.create.event.json +++ b/test/messages/taas.resourcebooking.create.event.json @@ -1 +1 @@ -{"topic":"taas.resourcebooking.create","originator":"taas-api","timestamp":"2020-11-05T19:00:25.038Z","mime-type":"application/json","payload":{"projectId":21,"userId":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","jobId":"ffbc24f7-301e-48d3-bf01-c056916056a2","startDate":"2020-09-27T04:17:23.131Z","endDate":"2020-09-27T04:17:23.131Z","memberRate":13.23,"customerRate":13,"rateType":"hourly","id":"60d97713-8621-476e-b006-7cb9589c7777","createdAt":"2020-11-05T19:00:23.036Z","createdBy":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","status":"sourcing"}} \ No newline at end of file +{"topic":"taas.resourcebooking.create","originator":"taas-api","timestamp":"2020-11-05T19:00:25.038Z","mime-type":"application/json","payload":{"projectId":21,"userId":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","jobId":"ffbc24f7-301e-48d3-bf01-c056916056a2","startDate":"2020-09-27T04:17:23.131Z","endDate":"2020-09-27T04:17:23.131Z","memberRate":13.23,"customerRate":13,"rateType":"hourly","id":"60d97713-8621-476e-b006-7cb9589c7777","createdAt":"2020-11-05T19:00:23.036Z","createdBy":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","status":"assigned"}} \ No newline at end of file From c9661386fa06a8bf0074d8e78bd5caee6d4e3823 Mon Sep 17 00:00:00 2001 From: narekcat Date: Mon, 19 Apr 2021 01:05:05 +0400 Subject: [PATCH 05/11] Final fixes for adding work period payments. --- .../WorkPeriodPaymentProcessorService.js | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/services/WorkPeriodPaymentProcessorService.js b/src/services/WorkPeriodPaymentProcessorService.js index 45fd6c5..1f6cc54 100644 --- a/src/services/WorkPeriodPaymentProcessorService.js +++ b/src/services/WorkPeriodPaymentProcessorService.js @@ -18,19 +18,19 @@ const esClient = helper.getESClient() */ async function processCreate (message, transactionId) { const data = message.payload - const workPeriod = await esClient.get({ + const workPeriod = await esClient.getExtra({ index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), id: data.workPeriodId }) - const payments = _.isArray(workPeriod.body._source.payments) ? workPeriod.body._source.payments : [] + const payments = _.isArray(workPeriod.body.payments) ? workPeriod.body.payments : [] payments.push(data) - return esClient.update({ + return esClient.updateExtra({ index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), id: data.workPeriodId, transactionId, body: { - doc: _.assign(workPeriod.body._source, { payments }) + doc: _.assign(workPeriod.body, { payments }) }, refresh: constants.esRefreshOption }) @@ -77,12 +77,15 @@ async function processUpdate (message, transactionId) { } } }) + if (!workPeriod.body.hits.total.value) { + throw new Error(`id: ${data.id} "WorkPeriodPayments" not found`) + } let payments // if WorkPeriodPayment's workPeriodId changed then it must be deleted from the old WorkPeriod // and added to the new WorkPeriod if (workPeriod.body.hits.hits[0]._source.id !== data.workPeriodId) { payments = _.filter(workPeriod.body.hits.hits[0]._source.payments, (payment) => payment.id !== data.id) - await esClient.update({ + await esClient.updateExtra({ index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), id: workPeriod.body.hits.hits[0]._source.id, transactionId, @@ -90,18 +93,18 @@ async function processUpdate (message, transactionId) { doc: _.assign(workPeriod.body.hits.hits[0]._source, { payments }) } }) - workPeriod = await esClient.get({ + workPeriod = await esClient.getExtra({ index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), id: data.workPeriodId }) - payments = _.isArray(workPeriod.body._source.payments) ? workPeriod.body._source.payments : [] + payments = _.isArray(workPeriod.body.payments) ? workPeriod.body.payments : [] payments.push(data) - return esClient.update({ + return esClient.updateExtra({ index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), id: data.workPeriodId, transactionId, body: { - doc: _.assign(workPeriod.body._source, { payments }) + doc: _.assign(workPeriod.body, { payments }) } }) } @@ -113,7 +116,7 @@ async function processUpdate (message, transactionId) { return payment }) - return esClient.update({ + return esClient.updateExtra({ index: config.get('esConfig.ES_INDEX_WORK_PERIOD'), id: data.workPeriodId, transactionId, From 130d37aac484fa1d0f8a67c5e0d6d12d7a795574 Mon Sep 17 00:00:00 2001 From: xxcxy Date: Wed, 21 Apr 2021 13:59:43 +0800 Subject: [PATCH 06/11] part1 --- README.md | 1 + config/default.js | 4 +- local/docker-compose.yml | 2 +- src/app.js | 5 +- src/bootstrap.js | 5 ++ src/common/constants.js | 5 ++ src/scripts/createIndex.js | 16 +++++ src/services/InterviewProcessorService.js | 79 +++++++++++++++++++++++ 8 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 src/services/InterviewProcessorService.js diff --git a/README.md b/README.md index d8409ab..07e97c6 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ The following parameters can be set in config files or in env variables: - `topics.TAAS_WORK_PERIOD_CREATE_TOPIC`: the create work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_UPDATE_TOPIC`: the update work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_DELETE_TOPIC`: the delete work period entity Kafka message topic +- `topics.TAAS_INTERVIEW_REQUEST_TOPIC`: the request interview entity Kafka message topic - `esConfig.HOST`: Elasticsearch host - `esConfig.AWS_REGION`: The Amazon region to use when using AWS Elasticsearch service - `esConfig.ELASTICCLOUD.id`: The elastic cloud id, if your elasticsearch instance is hosted on elastic cloud. DO NOT provide a value for ES_HOST if you are using this diff --git a/config/default.js b/config/default.js index 446ab4e..478c719 100644 --- a/config/default.js +++ b/config/default.js @@ -31,7 +31,9 @@ module.exports = { // topics for work period service TAAS_WORK_PERIOD_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_CREATE_TOPIC || 'taas.workperiod.create', TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update', - TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete' + TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete', + // topics for interview service + TAAS_INTERVIEW_REQUEST_TOPIC: process.env.TAAS_INTERVIEW_REQUEST_TOPIC || 'taas.interview.request' }, esConfig: { diff --git a/local/docker-compose.yml b/local/docker-compose.yml index 5d2d803..5f355f3 100644 --- a/local/docker-compose.yml +++ b/local/docker-compose.yml @@ -12,7 +12,7 @@ services: - "9092:9092" environment: KAFKA_ADVERTISED_HOST_NAME: localhost - KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1" + KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.interview.request:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 esearch: image: elasticsearch:7.7.1 diff --git a/src/app.js b/src/app.js index 1d3ae47..b4ee7bb 100644 --- a/src/app.js +++ b/src/app.js @@ -13,6 +13,7 @@ const JobProcessorService = require('./services/JobProcessorService') const JobCandidateProcessorService = require('./services/JobCandidateProcessorService') const ResourceBookingProcessorService = require('./services/ResourceBookingProcessorService') const WorkPeriodProcessorService = require('./services/WorkPeriodProcessorService') +const InterviewProcessorService = require('./services/InterviewProcessorService') const Mutex = require('async-mutex').Mutex const events = require('events') @@ -43,7 +44,9 @@ const topicServiceMapping = { // work period [config.topics.TAAS_WORK_PERIOD_CREATE_TOPIC]: WorkPeriodProcessorService.processCreate, [config.topics.TAAS_WORK_PERIOD_UPDATE_TOPIC]: WorkPeriodProcessorService.processUpdate, - [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete + [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete, + // interview + [config.topics.TAAS_INTERVIEW_REQUEST_TOPIC]: InterviewProcessorService.processRequestInterview } // Start kafka consumer diff --git a/src/bootstrap.js b/src/bootstrap.js index d25de1a..bb0761a 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -1,7 +1,11 @@ const Joi = require('@hapi/joi') const config = require('config') +const _ = require('lodash') +const { Interview } = require('../src/common/constants') const constants = require('./common/constants') +const allowedInterviewStatuses = _.values(Interview.Status) + global.Promise = require('bluebird') Joi.rateType = () => Joi.string().valid('hourly', 'daily', 'weekly', 'monthly') @@ -10,6 +14,7 @@ Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist Joi.workload = () => Joi.string().valid('full-time', 'fractional') Joi.title = () => Joi.string().max(128) Joi.paymentStatus = () => Joi.string().valid('pending', 'partially-completed', 'completed', 'cancelled') +Joi.interviewStatus = () => Joi.string().valid(...allowedInterviewStatuses) // 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. diff --git a/src/common/constants.js b/src/common/constants.js index 62d8720..0d47cb4 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -16,5 +16,10 @@ module.exports = { JobCandidateCreate: 'jobcandidate:create', JobCandidateUpdate: 'jobcandidate:update' } + }, + Interview: { + Status: { + Requested: 'Requested' + } } } diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index 095633e..6ba13e0 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -46,6 +46,22 @@ async function createIndex () { status: { type: 'keyword' }, externalId: { type: 'keyword' }, resume: { type: 'text' }, + interviews: { + type: 'nested', + properties: { + id: { type: 'keyword' }, + jobCandidateId: { type: 'keyword' }, + googleCalendarId: { type: 'keyword' }, + customMessage: { type: 'text' }, + xaiTemplate: { type: 'keyword' }, + round: { type: 'integer' }, + status: { type: 'keyword' }, + createdAt: { type: 'date' }, + createdBy: { type: 'keyword' }, + updatedAt: { type: 'date' }, + updatedBy: { type: 'keyword' } + } + }, createdAt: { type: 'date' }, createdBy: { type: 'keyword' }, updatedAt: { type: 'date' }, diff --git a/src/services/InterviewProcessorService.js b/src/services/InterviewProcessorService.js new file mode 100644 index 0000000..d02fe07 --- /dev/null +++ b/src/services/InterviewProcessorService.js @@ -0,0 +1,79 @@ +/** + * Interview Processor Service + */ + +const Joi = require('@hapi/joi') +const logger = require('../common/logger') +const helper = require('../common/helper') +const constants = require('../common/constants') +const config = require('config') + +const esClient = helper.getESClient() + +/** + * Updates jobCandidate via a painless script + * + * @param {String} jobCandidateId job candidate id + * @param {String} script script definition + * @param {String} transactionId transaction id + */ +async function updateJobCandidateViaScript (jobCandidateId, script, transactionId) { + await esClient.updateExtra({ + index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), + id: jobCandidateId, + transactionId, + body: { script }, + refresh: constants.esRefreshOption + }) +} + +/** + * Process request interview entity message. + * Creates an interview record under jobCandidate. + * + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processRequestInterview (message, transactionId) { + const interview = message.payload + // add interview in collection if there's already an existing collection + // or initiate a new one with this interview + const script = { + source: ` + ctx._source.containsKey("interviews") + ? ctx._source.interviews.add(params.interview) + : ctx._source.interviews = [params.interview] + `, + params: { interview } + } + await updateJobCandidateViaScript(interview.jobCandidateId, script, transactionId) +} + +processRequestInterview.schema = { + message: Joi.object().keys({ + topic: Joi.string().required(), + originator: Joi.string().required(), + timestamp: Joi.date().required(), + 'mime-type': Joi.string().required(), + payload: Joi.object().keys({ + id: Joi.string().uuid().required(), + jobCandidateId: Joi.string().uuid().required(), + googleCalendarId: Joi.string().allow(null), + customMessage: Joi.string().allow(null), + xaiTemplate: Joi.string().required(), + round: Joi.number().integer().positive().required(), + status: Joi.interviewStatus().required(), + createdAt: Joi.date().required(), + createdBy: Joi.string().uuid().required(), + updatedAt: Joi.date().allow(null), + updatedBy: Joi.string().uuid().allow(null) + }).required() + }).required(), + transactionId: Joi.string().required() +} + +module.exports = { + processRequestInterview +} + +logger.buildService(module.exports, 'InterviewProcessorService') From 47ae415d081b8e08c320d8ab078e67dc7aa0adab Mon Sep 17 00:00:00 2001 From: xxcxy Date: Wed, 21 Apr 2021 14:00:37 +0800 Subject: [PATCH 07/11] part2 --- README.md | 1 + config/default.js | 3 +- local/docker-compose.yml | 2 +- src/app.js | 3 +- src/common/constants.js | 7 ++- src/scripts/createIndex.js | 2 + src/services/InterviewProcessorService.js | 65 ++++++++++++++++++++++- 7 files changed, 77 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 07e97c6..519f60c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ The following parameters can be set in config files or in env variables: - `topics.TAAS_WORK_PERIOD_UPDATE_TOPIC`: the update work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_DELETE_TOPIC`: the delete work period entity Kafka message topic - `topics.TAAS_INTERVIEW_REQUEST_TOPIC`: the request interview entity Kafka message topic +- `topics.TAAS_INTERVIEW_UPDATE_TOPIC`: the update interview entity Kafka message topic - `esConfig.HOST`: Elasticsearch host - `esConfig.AWS_REGION`: The Amazon region to use when using AWS Elasticsearch service - `esConfig.ELASTICCLOUD.id`: The elastic cloud id, if your elasticsearch instance is hosted on elastic cloud. DO NOT provide a value for ES_HOST if you are using this diff --git a/config/default.js b/config/default.js index 478c719..9e53a7e 100644 --- a/config/default.js +++ b/config/default.js @@ -33,7 +33,8 @@ module.exports = { TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update', TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete', // topics for interview service - TAAS_INTERVIEW_REQUEST_TOPIC: process.env.TAAS_INTERVIEW_REQUEST_TOPIC || 'taas.interview.request' + TAAS_INTERVIEW_REQUEST_TOPIC: process.env.TAAS_INTERVIEW_REQUEST_TOPIC || 'taas.interview.requested', + TAAS_INTERVIEW_UPDATE_TOPIC: process.env.TAAS_INTERVIEW_UPDATE_TOPIC || 'taas.interview.update' }, esConfig: { diff --git a/local/docker-compose.yml b/local/docker-compose.yml index 5f355f3..d5c65ac 100644 --- a/local/docker-compose.yml +++ b/local/docker-compose.yml @@ -12,7 +12,7 @@ services: - "9092:9092" environment: KAFKA_ADVERTISED_HOST_NAME: localhost - KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.interview.request:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1" + KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.interview.requested:1:1,taas.interview.update:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 esearch: image: elasticsearch:7.7.1 diff --git a/src/app.js b/src/app.js index b4ee7bb..471acb5 100644 --- a/src/app.js +++ b/src/app.js @@ -46,7 +46,8 @@ const topicServiceMapping = { [config.topics.TAAS_WORK_PERIOD_UPDATE_TOPIC]: WorkPeriodProcessorService.processUpdate, [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete, // interview - [config.topics.TAAS_INTERVIEW_REQUEST_TOPIC]: InterviewProcessorService.processRequestInterview + [config.topics.TAAS_INTERVIEW_REQUEST_TOPIC]: InterviewProcessorService.processRequestInterview, + [config.topics.TAAS_INTERVIEW_UPDATE_TOPIC]: InterviewProcessorService.processUpdateInterview } // Start kafka consumer diff --git a/src/common/constants.js b/src/common/constants.js index 0d47cb4..d7f16ec 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -19,7 +19,12 @@ module.exports = { }, Interview: { Status: { - Requested: 'Requested' + Scheduling: 'Scheduling', + Scheduled: 'Scheduled', + RequestedForReschedule: 'Requested for reschedule', + Rescheduled: 'Rescheduled', + Completed: 'Completed', + Cancelled: 'Cancelled' } } } diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index 6ba13e0..8303f3f 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -52,6 +52,8 @@ async function createIndex () { id: { type: 'keyword' }, jobCandidateId: { type: 'keyword' }, googleCalendarId: { type: 'keyword' }, + startTimestamp: { type: 'date' }, + attendeesList: { type: 'keyword' }, customMessage: { type: 'text' }, xaiTemplate: { type: 'keyword' }, round: { type: 'integer' }, diff --git a/src/services/InterviewProcessorService.js b/src/services/InterviewProcessorService.js index d02fe07..15af5ef 100644 --- a/src/services/InterviewProcessorService.js +++ b/src/services/InterviewProcessorService.js @@ -2,6 +2,7 @@ * Interview Processor Service */ +const _ = require('lodash') const Joi = require('@hapi/joi') const logger = require('../common/logger') const helper = require('../common/helper') @@ -66,14 +67,74 @@ processRequestInterview.schema = { createdAt: Joi.date().required(), createdBy: Joi.string().uuid().required(), updatedAt: Joi.date().allow(null), - updatedBy: Joi.string().uuid().allow(null) + updatedBy: Joi.string().uuid().allow(null), + attendeesList: Joi.array().items(Joi.string().email()).allow(null), + startTimestamp: Joi.date().allow(null) + }).required() + }).required(), + transactionId: Joi.string().required() +} + +/** + * Process update interview entity message. + * Update an interview record under jobCandidate. + * + * @param {Object} message the kafka message + * @param {String} transactionId + */ +async function processUpdateInterview (message, transactionId) { + const data = message.payload + const { body: jobCandidate } = await esClient.getExtra({ + index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), + id: data.jobCandidateId + }) + const interviews = jobCandidate.interviews || [] + const index = _.findIndex(interviews, ['id', data.id]) + if (index === -1) { + interviews.push(data) + } else { + interviews.splice(index, 1, data) + } + jobCandidate.interviews = interviews + await esClient.updateExtra({ + index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), + id: data.jobCandidateId, + transactionId, + body: { + doc: jobCandidate + }, + refresh: constants.esRefreshOption + }) +} + +processUpdateInterview.schema = { + message: Joi.object().keys({ + topic: Joi.string().required(), + originator: Joi.string().required(), + timestamp: Joi.date().required(), + 'mime-type': Joi.string().required(), + payload: Joi.object().keys({ + id: Joi.string().uuid().required(), + jobCandidateId: Joi.string().uuid().required(), + googleCalendarId: Joi.string().allow(null), + customMessage: Joi.string().allow(null), + xaiTemplate: Joi.string().required(), + round: Joi.number().integer().positive().required(), + status: Joi.interviewStatus().required(), + createdAt: Joi.date().required(), + createdBy: Joi.string().uuid().required(), + updatedAt: Joi.date().required(), + updatedBy: Joi.string().uuid().required(), + attendeesList: Joi.array().items(Joi.string().email()).allow(null), + startTimestamp: Joi.date().allow(null) }).required() }).required(), transactionId: Joi.string().required() } module.exports = { - processRequestInterview + processRequestInterview, + processUpdateInterview } logger.buildService(module.exports, 'InterviewProcessorService') From 4a6b647c04ce4012e635adfded408d72ceff4806 Mon Sep 17 00:00:00 2001 From: nkumar-topcoder <33625707+nkumar-topcoder@users.noreply.github.com> Date: Wed, 21 Apr 2021 13:58:40 +0530 Subject: [PATCH 08/11] Revert "Feature/interview scheduler" --- README.md | 2 - config/default.js | 3 - local/docker-compose.yml | 2 +- src/app.js | 4 - src/bootstrap.js | 5 - src/common/constants.js | 10 -- src/scripts/createIndex.js | 18 --- src/services/InterviewProcessorService.js | 140 ---------------------- 8 files changed, 1 insertion(+), 183 deletions(-) delete mode 100644 src/services/InterviewProcessorService.js diff --git a/README.md b/README.md index 9cf88c6..045684f 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ The following parameters can be set in config files or in env variables: - `topics.TAAS_WORK_PERIOD_CREATE_TOPIC`: the create work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_UPDATE_TOPIC`: the update work period entity Kafka message topic - `topics.TAAS_WORK_PERIOD_DELETE_TOPIC`: the delete work period entity Kafka message topic -- `topics.TAAS_INTERVIEW_REQUEST_TOPIC`: the request interview entity Kafka message topic -- `topics.TAAS_INTERVIEW_UPDATE_TOPIC`: the update interview entity Kafka message topic - `topics.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC`: the create work period payment entity Kafka message topic - `topics.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC`: the update work period payment entity Kafka message topic - `esConfig.HOST`: Elasticsearch host diff --git a/config/default.js b/config/default.js index d1f2fae..7a8dbf8 100644 --- a/config/default.js +++ b/config/default.js @@ -32,9 +32,6 @@ module.exports = { TAAS_WORK_PERIOD_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_CREATE_TOPIC || 'taas.workperiod.create', TAAS_WORK_PERIOD_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_UPDATE_TOPIC || 'taas.workperiod.update', TAAS_WORK_PERIOD_DELETE_TOPIC: process.env.TAAS_WORK_PERIOD_DELETE_TOPIC || 'taas.workperiod.delete', - // topics for interview service - TAAS_INTERVIEW_REQUEST_TOPIC: process.env.TAAS_INTERVIEW_REQUEST_TOPIC || 'taas.interview.requested', - TAAS_INTERVIEW_UPDATE_TOPIC: process.env.TAAS_INTERVIEW_UPDATE_TOPIC || 'taas.interview.update', // topics for work period payment service TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC || 'taas.workperiodpayment.create', TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC: process.env.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC || 'taas.workperiodpayment.update' diff --git a/local/docker-compose.yml b/local/docker-compose.yml index 3d01ede..35e9486 100644 --- a/local/docker-compose.yml +++ b/local/docker-compose.yml @@ -12,7 +12,7 @@ services: - "9092:9092" environment: KAFKA_ADVERTISED_HOST_NAME: localhost - KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.interview.requested:1:1,taas.interview.update:1:1,taas.workperiod.create:1:1,taas.workperiodpayment.create:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.workperiod.update:1:1,taas.workperiodpayment.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1,taas.workperiod.delete:1:1" + KAFKA_CREATE_TOPICS: "taas.job.create:1:1,taas.jobcandidate.create:1:1,taas.resourcebooking.create:1:1,taas.workperiod.create:1:1,taas.workperiodpayment.create:1:1,taas.job.update:1:1,taas.jobcandidate.update:1:1,taas.resourcebooking.update:1:1,taas.workperiod.update:1:1,taas.workperiodpayment.update:1:1,taas.job.delete:1:1,taas.jobcandidate.delete:1:1,taas.resourcebooking.delete:1:1,taas.workperiod.delete:1:1" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 esearch: image: elasticsearch:7.7.1 diff --git a/src/app.js b/src/app.js index e0f5a22..c38c03d 100644 --- a/src/app.js +++ b/src/app.js @@ -13,7 +13,6 @@ const JobProcessorService = require('./services/JobProcessorService') const JobCandidateProcessorService = require('./services/JobCandidateProcessorService') const ResourceBookingProcessorService = require('./services/ResourceBookingProcessorService') const WorkPeriodProcessorService = require('./services/WorkPeriodProcessorService') -const InterviewProcessorService = require('./services/InterviewProcessorService') const WorkPeriodPaymentProcessorService = require('./services/WorkPeriodPaymentProcessorService') const Mutex = require('async-mutex').Mutex const events = require('events') @@ -46,9 +45,6 @@ const topicServiceMapping = { [config.topics.TAAS_WORK_PERIOD_CREATE_TOPIC]: WorkPeriodProcessorService.processCreate, [config.topics.TAAS_WORK_PERIOD_UPDATE_TOPIC]: WorkPeriodProcessorService.processUpdate, [config.topics.TAAS_WORK_PERIOD_DELETE_TOPIC]: WorkPeriodProcessorService.processDelete, - // interview - [config.topics.TAAS_INTERVIEW_REQUEST_TOPIC]: InterviewProcessorService.processRequestInterview, - [config.topics.TAAS_INTERVIEW_UPDATE_TOPIC]: InterviewProcessorService.processUpdateInterview, // work period payment [config.topics.TAAS_WORK_PERIOD_PAYMENT_CREATE_TOPIC]: WorkPeriodPaymentProcessorService.processCreate, [config.topics.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC]: WorkPeriodPaymentProcessorService.processUpdate diff --git a/src/bootstrap.js b/src/bootstrap.js index 8f23fe3..794ab83 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -1,11 +1,7 @@ const Joi = require('@hapi/joi') const config = require('config') -const _ = require('lodash') -const { Interview } = require('../src/common/constants') const constants = require('./common/constants') -const allowedInterviewStatuses = _.values(Interview.Status) - global.Promise = require('bluebird') Joi.rateType = () => Joi.string().valid('hourly', 'daily', 'weekly', 'monthly') @@ -15,7 +11,6 @@ Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist Joi.workload = () => Joi.string().valid('full-time', 'fractional') Joi.title = () => Joi.string().max(128) Joi.paymentStatus = () => Joi.string().valid('pending', 'partially-completed', 'completed', 'cancelled') -Joi.interviewStatus = () => Joi.string().valid(...allowedInterviewStatuses) 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. diff --git a/src/common/constants.js b/src/common/constants.js index d7f16ec..62d8720 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -16,15 +16,5 @@ module.exports = { JobCandidateCreate: 'jobcandidate:create', JobCandidateUpdate: 'jobcandidate:update' } - }, - Interview: { - Status: { - Scheduling: 'Scheduling', - Scheduled: 'Scheduled', - RequestedForReschedule: 'Requested for reschedule', - Rescheduled: 'Rescheduled', - Completed: 'Completed', - Cancelled: 'Cancelled' - } } } diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index 7142f03..fad96d3 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -46,24 +46,6 @@ async function createIndex () { status: { type: 'keyword' }, externalId: { type: 'keyword' }, resume: { type: 'text' }, - interviews: { - type: 'nested', - properties: { - id: { type: 'keyword' }, - jobCandidateId: { type: 'keyword' }, - googleCalendarId: { type: 'keyword' }, - startTimestamp: { type: 'date' }, - attendeesList: { type: 'keyword' }, - customMessage: { type: 'text' }, - xaiTemplate: { type: 'keyword' }, - round: { type: 'integer' }, - status: { type: 'keyword' }, - createdAt: { type: 'date' }, - createdBy: { type: 'keyword' }, - updatedAt: { type: 'date' }, - updatedBy: { type: 'keyword' } - } - }, createdAt: { type: 'date' }, createdBy: { type: 'keyword' }, updatedAt: { type: 'date' }, diff --git a/src/services/InterviewProcessorService.js b/src/services/InterviewProcessorService.js deleted file mode 100644 index 15af5ef..0000000 --- a/src/services/InterviewProcessorService.js +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Interview Processor Service - */ - -const _ = require('lodash') -const Joi = require('@hapi/joi') -const logger = require('../common/logger') -const helper = require('../common/helper') -const constants = require('../common/constants') -const config = require('config') - -const esClient = helper.getESClient() - -/** - * Updates jobCandidate via a painless script - * - * @param {String} jobCandidateId job candidate id - * @param {String} script script definition - * @param {String} transactionId transaction id - */ -async function updateJobCandidateViaScript (jobCandidateId, script, transactionId) { - await esClient.updateExtra({ - index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), - id: jobCandidateId, - transactionId, - body: { script }, - refresh: constants.esRefreshOption - }) -} - -/** - * Process request interview entity message. - * Creates an interview record under jobCandidate. - * - * @param {Object} message the kafka message - * @param {String} transactionId - */ -async function processRequestInterview (message, transactionId) { - const interview = message.payload - // add interview in collection if there's already an existing collection - // or initiate a new one with this interview - const script = { - source: ` - ctx._source.containsKey("interviews") - ? ctx._source.interviews.add(params.interview) - : ctx._source.interviews = [params.interview] - `, - params: { interview } - } - await updateJobCandidateViaScript(interview.jobCandidateId, script, transactionId) -} - -processRequestInterview.schema = { - message: Joi.object().keys({ - topic: Joi.string().required(), - originator: Joi.string().required(), - timestamp: Joi.date().required(), - 'mime-type': Joi.string().required(), - payload: Joi.object().keys({ - id: Joi.string().uuid().required(), - jobCandidateId: Joi.string().uuid().required(), - googleCalendarId: Joi.string().allow(null), - customMessage: Joi.string().allow(null), - xaiTemplate: Joi.string().required(), - round: Joi.number().integer().positive().required(), - status: Joi.interviewStatus().required(), - createdAt: Joi.date().required(), - createdBy: Joi.string().uuid().required(), - updatedAt: Joi.date().allow(null), - updatedBy: Joi.string().uuid().allow(null), - attendeesList: Joi.array().items(Joi.string().email()).allow(null), - startTimestamp: Joi.date().allow(null) - }).required() - }).required(), - transactionId: Joi.string().required() -} - -/** - * Process update interview entity message. - * Update an interview record under jobCandidate. - * - * @param {Object} message the kafka message - * @param {String} transactionId - */ -async function processUpdateInterview (message, transactionId) { - const data = message.payload - const { body: jobCandidate } = await esClient.getExtra({ - index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), - id: data.jobCandidateId - }) - const interviews = jobCandidate.interviews || [] - const index = _.findIndex(interviews, ['id', data.id]) - if (index === -1) { - interviews.push(data) - } else { - interviews.splice(index, 1, data) - } - jobCandidate.interviews = interviews - await esClient.updateExtra({ - index: config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), - id: data.jobCandidateId, - transactionId, - body: { - doc: jobCandidate - }, - refresh: constants.esRefreshOption - }) -} - -processUpdateInterview.schema = { - message: Joi.object().keys({ - topic: Joi.string().required(), - originator: Joi.string().required(), - timestamp: Joi.date().required(), - 'mime-type': Joi.string().required(), - payload: Joi.object().keys({ - id: Joi.string().uuid().required(), - jobCandidateId: Joi.string().uuid().required(), - googleCalendarId: Joi.string().allow(null), - customMessage: Joi.string().allow(null), - xaiTemplate: Joi.string().required(), - round: Joi.number().integer().positive().required(), - status: Joi.interviewStatus().required(), - createdAt: Joi.date().required(), - createdBy: Joi.string().uuid().required(), - updatedAt: Joi.date().required(), - updatedBy: Joi.string().uuid().required(), - attendeesList: Joi.array().items(Joi.string().email()).allow(null), - startTimestamp: Joi.date().allow(null) - }).required() - }).required(), - transactionId: Joi.string().required() -} - -module.exports = { - processRequestInterview, - processUpdateInterview -} - -logger.buildService(module.exports, 'InterviewProcessorService') From 6872051e917d9b9a3996664fb813eb3e1773afbf Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 22 Apr 2021 02:15:47 +0300 Subject: [PATCH 09/11] Resource Booking index to not store time, only dates --- .gitignore | 1 + src/scripts/createIndex.js | 4 ++-- .../ResourceBookingProcessorService.js | 6 +++-- .../taas.resourcebooking.create.event.json | 21 ++++++++++++++++- .../taas.resourcebooking.update.event.json | 23 ++++++++++++++++++- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 7d71a33..f00801a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ coverage .DS_Store .env api.env +.eslintrc.y*ml diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index fad96d3..33114fb 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -63,8 +63,8 @@ async function createIndex () { 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' }, diff --git a/src/services/ResourceBookingProcessorService.js b/src/services/ResourceBookingProcessorService.js index 4972afe..1dff5b4 100644 --- a/src/services/ResourceBookingProcessorService.js +++ b/src/services/ResourceBookingProcessorService.js @@ -37,8 +37,10 @@ processCreate.schema = { 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), + // eslint-disable-next-line no-useless-escape + startDate: Joi.string().regex(/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/).allow(null), + // eslint-disable-next-line no-useless-escape + endDate: Joi.string().regex(/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/).allow(null), memberRate: Joi.number().allow(null), customerRate: Joi.number().allow(null), rateType: Joi.rateType().required(), diff --git a/test/messages/taas.resourcebooking.create.event.json b/test/messages/taas.resourcebooking.create.event.json index 92ec817..31d6217 100644 --- a/test/messages/taas.resourcebooking.create.event.json +++ b/test/messages/taas.resourcebooking.create.event.json @@ -1 +1,20 @@ -{"topic":"taas.resourcebooking.create","originator":"taas-api","timestamp":"2020-11-05T19:00:25.038Z","mime-type":"application/json","payload":{"projectId":21,"userId":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","jobId":"ffbc24f7-301e-48d3-bf01-c056916056a2","startDate":"2020-09-27T04:17:23.131Z","endDate":"2020-09-27T04:17:23.131Z","memberRate":13.23,"customerRate":13,"rateType":"hourly","id":"60d97713-8621-476e-b006-7cb9589c7777","createdAt":"2020-11-05T19:00:23.036Z","createdBy":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","status":"assigned"}} \ No newline at end of file +{ + "topic": "taas.resourcebooking.create", + "originator": "taas-api", + "timestamp": "2020-11-05T19:00:25.038Z", + "mime-type": "application/json", + "payload": { + "projectId": 21, + "userId": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "jobId": "ffbc24f7-301e-48d3-bf01-c056916056a2", + "startDate": "2020-09-27", + "endDate": "2020-09-27", + "memberRate": 13.23, + "customerRate": 13, + "rateType": "hourly", + "id": "60d97713-8621-476e-b006-7cb9589c7777", + "createdAt": "2020-11-05T19:00:23.036Z", + "createdBy": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "status": "assigned" + } +} \ No newline at end of file diff --git a/test/messages/taas.resourcebooking.update.event.json b/test/messages/taas.resourcebooking.update.event.json index 2c07a4e..e45fc86 100644 --- a/test/messages/taas.resourcebooking.update.event.json +++ b/test/messages/taas.resourcebooking.update.event.json @@ -1 +1,22 @@ -{"topic":"taas.resourcebooking.update","originator":"taas-api","timestamp":"2020-11-05T19:00:26.407Z","mime-type":"application/json","payload":{"id":"60d97713-8621-476e-b006-7cb9589c7777","projectId":21,"userId":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","jobId":"ffbc24f7-301e-48d3-bf01-c056916056a2","startDate":"2020-09-27T04:17:23.131Z","endDate":"2020-09-27T04:17:23.131Z","memberRate":13.23,"customerRate":13,"rateType":"hourly","status":"assigned","updatedAt":"2020-11-05T19:00:25.062Z","updatedBy":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a","createdAt":"2020-11-05T19:00:16.268Z","createdBy":"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a"}} \ No newline at end of file +{ + "topic": "taas.resourcebooking.update", + "originator": "taas-api", + "timestamp": "2020-11-05T19:00:26.407Z", + "mime-type": "application/json", + "payload": { + "id": "60d97713-8621-476e-b006-7cb9589c7777", + "projectId": 21, + "userId": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "jobId": "ffbc24f7-301e-48d3-bf01-c056916056a2", + "startDate": "2020-09-27", + "endDate": "2020-09-27", + "memberRate": 13.23, + "customerRate": 13, + "rateType": "hourly", + "status": "assigned", + "updatedAt": "2020-11-05T19:00:25.062Z", + "updatedBy": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "createdAt": "2020-11-05T19:00:16.268Z", + "createdBy": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a" + } +} \ No newline at end of file From e7c3c6b7b710cd3258f0f195cd588c0b0367a427 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 22 Apr 2021 02:26:08 +0300 Subject: [PATCH 10/11] fix comment --- src/services/ResourceBookingProcessorService.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/ResourceBookingProcessorService.js b/src/services/ResourceBookingProcessorService.js index 1dff5b4..f507bde 100644 --- a/src/services/ResourceBookingProcessorService.js +++ b/src/services/ResourceBookingProcessorService.js @@ -37,9 +37,7 @@ processCreate.schema = { projectId: Joi.number().integer().required(), userId: Joi.string().uuid().required(), jobId: Joi.string().uuid().allow(null), - // eslint-disable-next-line no-useless-escape startDate: Joi.string().regex(/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/).allow(null), - // eslint-disable-next-line no-useless-escape endDate: Joi.string().regex(/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/).allow(null), memberRate: Joi.number().allow(null), customerRate: Joi.number().allow(null), From 2665ac5060f31c8e6de760a42624750b8fc53405 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Thu, 22 Apr 2021 20:36:04 +0800 Subject: [PATCH 11/11] Use billing account for payments --- src/scripts/createIndex.js | 2 ++ src/services/ResourceBookingProcessorService.js | 3 ++- src/services/WorkPeriodPaymentProcessorService.js | 1 + test/messages/taas.resourcebooking.create.event.json | 5 +++-- test/messages/taas.resourcebooking.update.event.json | 3 ++- test/messages/taas.workperiod.create.event.json | 3 ++- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/scripts/createIndex.js b/src/scripts/createIndex.js index 33114fb..c4601ee 100644 --- a/src/scripts/createIndex.js +++ b/src/scripts/createIndex.js @@ -68,6 +68,7 @@ async function createIndex () { memberRate: { type: 'float' }, customerRate: { type: 'float' }, rateType: { type: 'keyword' }, + billingAccountId: { type: 'integer' }, createdAt: { type: 'date' }, createdBy: { type: 'keyword' }, updatedAt: { type: 'date' }, @@ -98,6 +99,7 @@ async function createIndex () { challengeId: { type: 'keyword' }, amount: { type: 'float' }, status: { type: 'keyword' }, + billingAccountId: { type: 'integer' }, createdAt: { type: 'date' }, createdBy: { type: 'keyword' }, updatedAt: { type: 'date' }, diff --git a/src/services/ResourceBookingProcessorService.js b/src/services/ResourceBookingProcessorService.js index f507bde..f407b2b 100644 --- a/src/services/ResourceBookingProcessorService.js +++ b/src/services/ResourceBookingProcessorService.js @@ -46,7 +46,8 @@ processCreate.schema = { createdBy: Joi.string().uuid().required(), updatedAt: Joi.date().allow(null), updatedBy: Joi.string().uuid().allow(null), - status: Joi.resourceBookingStatus().required() + status: Joi.resourceBookingStatus().required(), + billingAccountId: Joi.number().allow(null) }).required() }).required(), transactionId: Joi.string().required() diff --git a/src/services/WorkPeriodPaymentProcessorService.js b/src/services/WorkPeriodPaymentProcessorService.js index 1f6cc54..d336379 100644 --- a/src/services/WorkPeriodPaymentProcessorService.js +++ b/src/services/WorkPeriodPaymentProcessorService.js @@ -48,6 +48,7 @@ processCreate.schema = { challengeId: Joi.string().uuid().required(), amount: Joi.number().greater(0).allow(null), status: Joi.workPeriodPaymentStatus().required(), + billingAccountId: Joi.number().allow(null), createdAt: Joi.date().required(), createdBy: Joi.string().uuid().required(), updatedAt: Joi.date().allow(null), diff --git a/test/messages/taas.resourcebooking.create.event.json b/test/messages/taas.resourcebooking.create.event.json index 31d6217..2f3de0a 100644 --- a/test/messages/taas.resourcebooking.create.event.json +++ b/test/messages/taas.resourcebooking.create.event.json @@ -15,6 +15,7 @@ "id": "60d97713-8621-476e-b006-7cb9589c7777", "createdAt": "2020-11-05T19:00:23.036Z", "createdBy": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", - "status": "assigned" + "status": "assigned", + "billingAccountId": 80000071 } -} \ No newline at end of file +} diff --git a/test/messages/taas.resourcebooking.update.event.json b/test/messages/taas.resourcebooking.update.event.json index e45fc86..2b96229 100644 --- a/test/messages/taas.resourcebooking.update.event.json +++ b/test/messages/taas.resourcebooking.update.event.json @@ -14,9 +14,10 @@ "customerRate": 13, "rateType": "hourly", "status": "assigned", + "billingAccountId": 80000071, "updatedAt": "2020-11-05T19:00:25.062Z", "updatedBy": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", "createdAt": "2020-11-05T19:00:16.268Z", "createdBy": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a" } -} \ No newline at end of file +} diff --git a/test/messages/taas.workperiod.create.event.json b/test/messages/taas.workperiod.create.event.json index 7afea61..3c2d286 100644 --- a/test/messages/taas.workperiod.create.event.json +++ b/test/messages/taas.workperiod.create.event.json @@ -14,9 +14,10 @@ "projectId": 111, "userHandle": "pshah_manager", "id": "926040c4-1709-4de2-b2b6-52adf6e5e72d", + "billingAccountId": 80000071 "createdBy": "00000000-0000-0000-0000-000000000000", "updatedAt": "2021-03-30T20:24:17.541Z", "createdAt": "2021-03-30T20:24:17.541Z", "updatedBy": null } -} \ No newline at end of file +}