Skip to content

Commit 30c627a

Browse files
committed
calculate daysWorked
1 parent 4064e5e commit 30c627a

File tree

6 files changed

+582
-368
lines changed

6 files changed

+582
-368
lines changed

src/common/helper.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,8 +953,8 @@ async function postEvent (topic, payload, options = {}) {
953953
payload
954954
}
955955
if (options.key) {
956-
message.key = options.key
957-
}
956+
message.key = options.key
957+
}
958958
await client.postEvent(message)
959959
await eventDispatcher.handleEvent(topic, { value: payload, options })
960960
}

src/eventHandlers/ResourceBookingEventHandler.js

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,45 @@ async function updateWorkPeriods (payload) {
176176
const workPeriodsToRemove = _.differenceBy(workPeriods, newWorkPeriods, 'startDate')
177177
// find which workperiods should be created
178178
const workPeriodsToAdd = _.differenceBy(newWorkPeriods, workPeriods, 'startDate')
179-
// find which workperiods' daysWorked propery should be updated
180-
let workPeriodsToUpdate = _.intersectionBy(newWorkPeriods, workPeriods, 'startDate')
181-
// find which workperiods' daysWorked property is preset and exceeds the possible maximum
182-
workPeriodsToUpdate = _.differenceWith(workPeriodsToUpdate, workPeriods, (a, b) => b.startDate === a.startDate && _.defaultTo(b.daysWorked, a.daysWorked) <= a.daysWorked)
183-
// include id
184-
workPeriodsToUpdate = _.map(workPeriodsToUpdate, wpu => {
185-
wpu.id = _.filter(workPeriods, ['startDate', wpu.startDate])[0].id
186-
return wpu
187-
})
179+
// find which workperiods' daysWorked property should be evaluated for changes
180+
const IntersectedWorkPeriods = _.intersectionBy(newWorkPeriods, workPeriods, 'startDate')
181+
let workPeriodsToUpdate = []
182+
if (IntersectedWorkPeriods.length > 0) {
183+
// We only need check for first and last ones of intersected workPeriods
184+
// The ones at the middle won't be updated and their daysWorked value will stay the same
185+
if (payload.options.oldValue.startDate !== payload.value.startDate) {
186+
const firstWeek = _.minBy(IntersectedWorkPeriods, 'startDate')
187+
const originalFirstWeek = _.find(workPeriods, ['startDate', firstWeek.startDate])
188+
// recalculate daysWorked for the first week of existent workPeriods
189+
if (firstWeek.startDate === _.minBy(workPeriods, 'startDate').startDate) {
190+
workPeriodsToUpdate.push(_.assign(firstWeek, { id: originalFirstWeek.id }))
191+
// if first of intersected workPeriods is not the first one of existent workPeriods
192+
// we only check if it's daysWorked exceeds the possible maximum
193+
} else if (originalFirstWeek.daysWorked > firstWeek.daysWorked) {
194+
workPeriodsToUpdate.push(_.assign(firstWeek, { id: originalFirstWeek.id }))
195+
}
196+
}
197+
if (payload.options.oldValue.endDate !== payload.value.endDate) {
198+
const lastWeek = _.maxBy(IntersectedWorkPeriods, 'startDate')
199+
const originalLastWeek = _.find(workPeriods, ['startDate', lastWeek.startDate])
200+
// recalculate daysWorked for the last week of existent workPeriods
201+
if (lastWeek.startDate === _.maxBy(workPeriods, 'startDate').startDate) {
202+
workPeriodsToUpdate.push(_.assign(lastWeek, { id: originalLastWeek.id }))
203+
// if last of intersected workPeriods is not the last one of existent workPeriods
204+
// we only check if it's daysWorked exceeds the possible maximum
205+
} else if (originalLastWeek.daysWorked > lastWeek.daysWorked) {
206+
workPeriodsToUpdate.push(_.assign(lastWeek, { id: originalLastWeek.id }))
207+
}
208+
}
209+
}
210+
// if intersected WP count is 1, this can result to duplicated WorkPeriods.
211+
// We should choose the one with higher daysWorked because, it's more likely
212+
// the WP we applied "first/last one of existent WPs" logic above.
213+
if (workPeriodsToUpdate.length === 2) {
214+
if (workPeriodsToUpdate[0].startDate === workPeriodsToUpdate[1].startDate) {
215+
workPeriodsToUpdate = [_.maxBy(workPeriodsToUpdate, 'daysWorked')]
216+
}
217+
}
188218
if (workPeriodsToRemove.length === 0 && workPeriodsToAdd.length === 0 && workPeriodsToUpdate.length === 0) {
189219
logger.debug({
190220
component: 'ResourceBookingEventHandler',
@@ -256,14 +286,16 @@ async function deleteWorkPeriods (payload) {
256286
* @returns {undefined}
257287
*/
258288
async function _createWorkPeriods (periods, resourceBookingId) {
259-
await Promise.all(_.map(periods, async period => await WorkPeriodService.createWorkPeriod(helper.getAuditM2Muser(),
260-
{
261-
resourceBookingId: resourceBookingId,
262-
startDate: period.startDate,
263-
endDate: period.endDate,
264-
daysWorked: null,
265-
paymentStatus: 'pending'
266-
})))
289+
for (const period of periods) {
290+
await WorkPeriodService.createWorkPeriod(helper.getAuditM2Muser(),
291+
{
292+
resourceBookingId: resourceBookingId,
293+
startDate: period.startDate,
294+
endDate: period.endDate,
295+
daysWorked: period.daysWorked,
296+
paymentStatus: 'pending'
297+
})
298+
}
267299
}
268300

269301
/**
@@ -272,11 +304,13 @@ async function _createWorkPeriods (periods, resourceBookingId) {
272304
* @returns {undefined}
273305
*/
274306
async function _updateWorkPeriods (periods) {
275-
await Promise.all(_.map(periods, async period => await WorkPeriodService.partiallyUpdateWorkPeriod(helper.getAuditM2Muser(),
276-
period.id,
277-
{
278-
daysWorked: period.daysWorked
279-
})))
307+
for (const period of periods) {
308+
await WorkPeriodService.partiallyUpdateWorkPeriod(helper.getAuditM2Muser(),
309+
period.id,
310+
{
311+
daysWorked: period.daysWorked
312+
})
313+
}
280314
}
281315

282316
/**
@@ -285,8 +319,9 @@ async function _updateWorkPeriods (periods) {
285319
* @returns {undefined}
286320
*/
287321
async function _deleteWorkPeriods (workPeriods) {
288-
await Promise.all(_.map(workPeriods,
289-
async workPeriod => await WorkPeriodService.deleteWorkPeriod(helper.getAuditM2Muser(), workPeriod.id)))
322+
for (const period of workPeriods) {
323+
await WorkPeriodService.deleteWorkPeriod(helper.getAuditM2Muser(), period.id)
324+
}
290325
}
291326

292327
/**

src/services/ResourceBookingService.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const moment = require('moment')
1818

1919
const ResourceBooking = models.ResourceBooking
2020
const WorkPeriod = models.WorkPeriod
21+
const WorkPeriodPayment = models.WorkPeriodPayment
2122
const esClient = helper.getESClient()
2223
const cachedModelFields = _cacheModelFields()
2324

@@ -168,27 +169,41 @@ async function _checkUserPermissionForGetResourceBooking (currentUser, projectId
168169
*/
169170
async function _ensurePaidWorkPeriodsNotDeleted (resourceBookingId, oldValue, newValue) {
170171
function _checkForPaidWorkPeriods (workPeriods) {
171-
const paidWorkPeriods = _.filter(workPeriods
172-
, workPeriod => _.includes(['completed', 'partially-completed'], workPeriod.paymentStatus))
172+
const paidWorkPeriods = _.filter(workPeriods, workPeriod => {
173+
// filter by WP and WPP status
174+
return (['completed', 'partially-completed', 'in-progress'].indexOf(workPeriod.paymentStatus) !== -1 ||
175+
_.some(workPeriod.payments, payment => ['completed', 'in-progress'].indexOf(payment.status) !== -1))
176+
})
173177
if (paidWorkPeriods.length > 0) {
174178
throw new errors.BadRequestError(`WorkPeriods with id of ${_.map(paidWorkPeriods, workPeriod => workPeriod.id)}
175-
has completed or partially-completed payment status.`)
179+
has completed, partially-completed or in-progress payment status.`)
176180
}
177181
}
178182
// find related workPeriods to evaluate the changes
179-
const workPeriods = await WorkPeriod.findAll({
183+
// We don't need to include WPP because WPP's status changes should
184+
// update WP's status. In case of any bug, it's better to check both WP
185+
// and WPP status for now.
186+
let workPeriods = await WorkPeriod.findAll({
180187
where: {
181188
resourceBookingId: resourceBookingId
182189
},
183-
raw: true
190+
attributes: ['id', 'paymentStatus', 'startDate', 'endDate'],
191+
include: [{
192+
model: WorkPeriodPayment,
193+
as: 'payments',
194+
required: false,
195+
attributes: ['status']
196+
}]
184197
})
198+
workPeriods = _.map(workPeriods, wp => wp.toJSON())
185199
// oldValue and newValue are not provided at deleteResourceBooking process
186200
if (_.isUndefined(oldValue) || _.isUndefined(newValue)) {
187201
_checkForPaidWorkPeriods(workPeriods)
188202
return
189203
}
190204
// We should not be able to change status of ResourceBooking to 'cancelled'
191-
// if there is at least one associated Work Period with paymentStatus 'partially-completed' or 'completed'.
205+
// if there is at least one associated Work Period with paymentStatus 'partially-completed', 'completed' or 'in-progress',
206+
// or any of it's WorkPeriodsPayment has status 'completed' or 'in-progress'.
192207
if (oldValue.status !== 'cancelled' && newValue.status === 'cancelled') {
193208
_checkForPaidWorkPeriods(workPeriods)
194209
// we have already checked all existing workPeriods
@@ -200,7 +215,8 @@ async function _ensurePaidWorkPeriodsNotDeleted (resourceBookingId, oldValue, ne
200215
_.isUndefined(newValue.endDate) ? oldValue.endDate : newValue.endDate)
201216
// find which workPeriods should be removed
202217
const workPeriodsToRemove = _.differenceBy(workPeriods, newWorkPeriods, 'startDate')
203-
// we can't delete workperiods with paymentStatus 'partially-completed' or 'completed'.
218+
// we can't delete workperiods with paymentStatus 'partially-completed', 'completed' or 'in-progress',
219+
// or any of it's WorkPeriodsPayment has status 'completed' or 'in-progress'.
204220
_checkForPaidWorkPeriods(workPeriodsToRemove)
205221
}
206222

src/services/WorkPeriodService.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ async function createWorkPeriod (currentUser, workPeriod) {
235235
}
236236
}
237237

238-
await helper.postEvent(config.TAAS_WORK_PERIOD_CREATE_TOPIC, created.toJSON(),{"key":workPeriod.resourceBookingId})
238+
await helper.postEvent(config.TAAS_WORK_PERIOD_CREATE_TOPIC, created.toJSON(), { key: workPeriod.resourceBookingId })
239239
return created.dataValues
240240
}
241241

@@ -289,8 +289,8 @@ async function updateWorkPeriod (currentUser, id, data) {
289289
}
290290
}
291291

292-
//await helper.postEvent(config.TAAS_WORK_PERIOD_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue })
293-
await helper.postEvent(config.TAAS_WORK_PERIOD_UPDATE_TOPIC, updated.toJSON(), {oldValue: oldValue, "key":data.resourceBookingId})
292+
// await helper.postEvent(config.TAAS_WORK_PERIOD_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue })
293+
await helper.postEvent(config.TAAS_WORK_PERIOD_UPDATE_TOPIC, updated.toJSON(), { oldValue: oldValue, key: data.resourceBookingId })
294294
return updated.dataValues
295295
}
296296

@@ -356,8 +356,11 @@ async function deleteWorkPeriod (currentUser, id) {
356356
}
357357

358358
const workPeriod = await WorkPeriod.findById(id, { withPayments: true })
359-
if (_.includes(['completed', 'partially-completed'], workPeriod.paymentStatus)) {
360-
throw new errors.BadRequestError("Can't delete WorkPeriod with paymentStatus completed or partially-completed")
359+
if (_.includes(['completed', 'partially-completed', 'in-progress'], workPeriod.paymentStatus)) {
360+
throw new errors.BadRequestError("Can't delete WorkPeriod with paymentStatus completed partially-completed, or in-progress")
361+
}
362+
if (_.some(workPeriod.payments, payment => ['completed', 'in-progress'].indexOf(payment.status) !== -1)) {
363+
throw new errors.BadRequestError("Can't delete WorkPeriod if any associated WorkPeriodsPayment has status completed or in-progress")
361364
}
362365
await models.WorkPeriodPayment.destroy({
363366
where: {

0 commit comments

Comments
 (0)