From 66a2ec285b33a5e02bff42c21be69c80f7d13beb Mon Sep 17 00:00:00 2001 From: yoution Date: Thu, 29 Jul 2021 07:45:13 +0800 Subject: [PATCH 1/2] fix: Edit payments fields #431 --- ...coder-bookings-api.postman_collection.json | 14 ++--- docs/swagger.yaml | 25 ++++++++ src/services/WorkPeriodPaymentService.js | 60 ++++++++++++++++++- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 8ee3ef14..c7fab8b9 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "0bd597ba-4bc2-4ea1-be33-45776b80c1ce", + "_postman_id": "9d8bfd2b-8864-49fd-8c6e-4cff10095cc3", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -17279,7 +17279,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"days\":1,\r\n \"amount\":2,\r\n \"memberRate\":1,\r\n \"customerRate\":3,\r\n \"billingAccountId\": 23\r\n}", "options": { "raw": { "language": "json" @@ -17325,7 +17325,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"days\":1,\r\n \"amount\":2,\r\n \"memberRate\":1,\r\n \"customerRate\":3,\r\n \"billingAccountId\": 23\r\n}", "options": { "raw": { "language": "json" @@ -17373,7 +17373,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"days\":1,\r\n \"amount\":2,\r\n \"memberRate\":1,\r\n \"customerRate\":3,\r\n \"billingAccountId\": 23\r\n}", "options": { "raw": { "language": "json" @@ -17421,7 +17421,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"days\":1,\r\n \"amount\":2,\r\n \"memberRate\":1,\r\n \"customerRate\":3,\r\n \"billingAccountId\": 23\r\n}", "options": { "raw": { "language": "json" @@ -17469,7 +17469,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"days\":1,\r\n \"amount\":2,\r\n \"memberRate\":1,\r\n \"customerRate\":3,\r\n \"billingAccountId\": 23\r\n}", "options": { "raw": { "language": "json" @@ -17517,7 +17517,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "raw": "{\r\n \"status\": \"cancelled\",\r\n \"days\":1,\r\n \"amount\":2,\r\n \"memberRate\":1,\r\n \"customerRate\":3,\r\n \"billingAccountId\": 23\r\n}", "options": { "raw": { "language": "json" diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 81e140b7..fee7280c 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -4887,6 +4887,30 @@ components: type: string enum: ["scheduled", "cancelled"] description: "The payment status." + memberRate: + type: integer + format: float + example: 13 + description: "The member rate." + customerRate: + type: integer + format: float + example: 13 + description: "The customer rate." + billingAccountId: + type: integer + example: 80000071 + description: "the billing account id for payments" + days: + type: integer + minimum: 0 + example: 3 + description: "The workdays to pay" + amount: + type: integer + format: float + example: 2 + description: "The amount to be paid." CheckRun: type: object properties: @@ -5873,3 +5897,4 @@ components: message: type: string + diff --git a/src/services/WorkPeriodPaymentService.js b/src/services/WorkPeriodPaymentService.js index 9a7a7780..852e8cc4 100644 --- a/src/services/WorkPeriodPaymentService.js +++ b/src/services/WorkPeriodPaymentService.js @@ -48,6 +48,38 @@ async function _createSingleWorkPeriodPayment (workPeriodPayment, createdBy) { return _createSingleWorkPeriodPaymentWithWorkPeriodAndResourceBooking(workPeriodPayment, createdBy, correspondingWorkPeriod.toJSON(), correspondingResourceBooking.toJSON()) } +/** + * Create single workPeriodPayment + * @param {Object} workPeriodPayment the workPeriodPayment to be created + * @param {String} createdBy the authUser id + * @returns {Object} the created workPeriodPayment + */ +async function _updateChallenge (challengeId, data) { + const body = {} + if (data.billingAccountId) { + body.billing = { + billingAccountId: _.toString(data.billingAccountId), + markup: 0 // for TaaS payments we always use 0 markup + } + } + if (data.amount) { + body.prizeSets = [{ + type: 'placement', + prizes: [{ type: 'USD', value: data.amount }] + }] + } + + if (data.billingAccountId || data.amount) { + try { + await helper.updateChallenge(challengeId, body) + logger.debug({ component: 'WorkPeriodPaymentService', context: 'updateChallenge', message: `Challenge with id ${challengeId} is updated` }) + } catch (err) { + logger.error({ component: 'WorkPeriodPaymentService', context: 'updateChallenge', message: err.response.text }) + throw new errors.BadRequestError(`Cannot update the the challenge: ${err.response.text}`) + } + } +} + /** * Create single workPeriodPayment * @param {Object} workPeriodPayment the workPeriodPayment to be created @@ -207,7 +239,15 @@ async function updateWorkPeriodPayment (currentUser, id, data) { _checkUserPermissionForCRUWorkPeriodPayment(currentUser) const workPeriodPayment = await WorkPeriodPayment.findById(id) + const oldValue = workPeriodPayment.toJSON() + + if (oldValue.status === 'in-progress') { + _.each(_.pick(data, ['amount', 'days', 'memberRate', 'customerRate', 'billingAccountId']), (value, key) => { + throw new errors.BadRequestError(`${key} cannot be updated when workPeriodPayment status is in-progress`) + }) + } + if (data.status === 'cancelled' && oldValue.status === 'in-progress') { throw new errors.BadRequestError('You cannot cancel a WorkPeriodPayment which is in-progress') } @@ -222,6 +262,19 @@ async function updateWorkPeriodPayment (currentUser, id, data) { throw new errors.BadRequestError('There is no available daysWorked to schedule a payment') } } + + if (data.days) { + const correspondingWorkPeriod = await helper.ensureWorkPeriodById(workPeriodPayment.workPeriodId) // ensure work period exists + const maxPossibleDays = correspondingWorkPeriod.daysWorked - correspondingWorkPeriod.daysPaid + if (data.days > maxPossibleDays) { + throw new errors.BadRequestError(`Days cannot be more than not paid days which is ${maxPossibleDays}`) + } + } + + if (oldValue.challengeId) { + await _updateChallenge(workPeriodPayment.challengeId, data) + } + data.updatedBy = await helper.getUserId(currentUser.userId) const updated = await workPeriodPayment.update(data) await helper.postEvent(config.TAAS_WORK_PERIOD_PAYMENT_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue, key: `workPeriodPayment.billingAccountId:${updated.billingAccountId}` }) @@ -243,7 +296,12 @@ partiallyUpdateWorkPeriodPayment.schema = Joi.object().keys({ currentUser: Joi.object().required(), id: Joi.string().uuid().required(), data: Joi.object().keys({ - status: Joi.workPeriodPaymentUpdateStatus() + status: Joi.workPeriodPaymentUpdateStatus(), + amount: Joi.number().min(0), + days: Joi.number().integer(), + memberRate: Joi.number().positive().required(), + customerRate: Joi.number().positive().allow(null), + billingAccountId: Joi.number().positive().integer().required() }).min(1).required() }).required() From 8949ec305094f640cca76545babe584fcc523a24 Mon Sep 17 00:00:00 2001 From: yoution Date: Thu, 29 Jul 2021 23:40:15 +0800 Subject: [PATCH 2/2] fix: issue #431 --- src/services/WorkPeriodPaymentService.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/services/WorkPeriodPaymentService.js b/src/services/WorkPeriodPaymentService.js index 852e8cc4..08839ae8 100644 --- a/src/services/WorkPeriodPaymentService.js +++ b/src/services/WorkPeriodPaymentService.js @@ -49,10 +49,10 @@ async function _createSingleWorkPeriodPayment (workPeriodPayment, createdBy) { } /** - * Create single workPeriodPayment - * @param {Object} workPeriodPayment the workPeriodPayment to be created - * @param {String} createdBy the authUser id - * @returns {Object} the created workPeriodPayment + * update challenge + * @param {String} challengeId the challenge id + * @param {Object} data the challenge update data + * @returns {undefined} */ async function _updateChallenge (challengeId, data) { const body = {} @@ -243,9 +243,10 @@ async function updateWorkPeriodPayment (currentUser, id, data) { const oldValue = workPeriodPayment.toJSON() if (oldValue.status === 'in-progress') { - _.each(_.pick(data, ['amount', 'days', 'memberRate', 'customerRate', 'billingAccountId']), (value, key) => { - throw new errors.BadRequestError(`${key} cannot be updated when workPeriodPayment status is in-progress`) - }) + const keys = _.keys(_.pick(data, ['amount', 'days', 'memberRate', 'customerRate', 'billingAccountId'])) + if (keys.length) { + throw new errors.BadRequestError(`${JSON.stringify(keys)} cannot be updated when workPeriodPayment status is in-progress`) + } } if (data.status === 'cancelled' && oldValue.status === 'in-progress') { @@ -265,13 +266,14 @@ async function updateWorkPeriodPayment (currentUser, id, data) { if (data.days) { const correspondingWorkPeriod = await helper.ensureWorkPeriodById(workPeriodPayment.workPeriodId) // ensure work period exists - const maxPossibleDays = correspondingWorkPeriod.daysWorked - correspondingWorkPeriod.daysPaid + const maxPossibleDays = correspondingWorkPeriod.daysWorked - correspondingWorkPeriod.daysPaid - oldValue.days if (data.days > maxPossibleDays) { throw new errors.BadRequestError(`Days cannot be more than not paid days which is ${maxPossibleDays}`) } } - if (oldValue.challengeId) { + // challengeId exist and skip dummy challenge + if (oldValue.challengeId && oldValue.challengeId !== '00000000-0000-0000-0000-000000000000') { await _updateChallenge(workPeriodPayment.challengeId, data) } @@ -299,9 +301,9 @@ partiallyUpdateWorkPeriodPayment.schema = Joi.object().keys({ status: Joi.workPeriodPaymentUpdateStatus(), amount: Joi.number().min(0), days: Joi.number().integer(), - memberRate: Joi.number().positive().required(), + memberRate: Joi.number().positive(), customerRate: Joi.number().positive().allow(null), - billingAccountId: Joi.number().positive().integer().required() + billingAccountId: Joi.number().positive().integer() }).min(1).required() }).required()