Skip to content

Commit b0242d8

Browse files
committed
refactor: various payment code improvements
1 parent 52469f3 commit b0242d8

10 files changed

+137
-48
lines changed

app-constants.js

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,21 @@ const ChallengeStatus = {
8484
COMPLETED: 'Completed'
8585
}
8686

87-
const PaymentStatus = {
87+
/**
88+
* Aggregate payment status for Work Period which is determined
89+
* based on the payments the Work Period has using `PaymentStatusRules`
90+
*/
91+
const AggregatePaymentStatus = {
8892
PENDING: 'pending',
8993
IN_PROGRESS: 'in-progress',
9094
PARTIALLY_COMPLETED: 'partially-completed',
9195
COMPLETED: 'completed',
92-
FAILED: 'failed',
9396
NO_DAYS: 'no-days'
9497
}
9598

99+
/**
100+
* `WorkPeriodPayment.status` - possible values
101+
*/
96102
const WorkPeriodPaymentStatus = {
97103
COMPLETED: 'completed',
98104
SCHEDULED: 'scheduled',
@@ -101,6 +107,32 @@ const WorkPeriodPaymentStatus = {
101107
CANCELLED: 'cancelled'
102108
}
103109

110+
/**
111+
* The rules how to determine WorkPeriod.paymentStatus based on the payments
112+
*
113+
* The top rule has priority over the bottom rules.
114+
*/
115+
const PaymentStatusRules = [
116+
{ paymentStatus: AggregatePaymentStatus.NO_DAYS, condition: { daysWorked: 0 } },
117+
{ paymentStatus: AggregatePaymentStatus.IN_PROGRESS, condition: { hasWorkPeriodPaymentStatus: [WorkPeriodPaymentStatus.SCHEDULED, WorkPeriodPaymentStatus.IN_PROGRESS] } },
118+
{ paymentStatus: AggregatePaymentStatus.COMPLETED, condition: { hasWorkPeriodPaymentStatus: [WorkPeriodPaymentStatus.COMPLETED], hasDueDays: false } },
119+
{ paymentStatus: AggregatePaymentStatus.PARTIALLY_COMPLETED, condition: { hasWorkPeriodPaymentStatus: [WorkPeriodPaymentStatus.COMPLETED], hasDueDays: true } },
120+
{ paymentStatus: AggregatePaymentStatus.PENDING, condition: { hasDueDays: true } }
121+
]
122+
123+
/**
124+
* The WorkPeriodPayment.status values which we take into account when calculate
125+
* aggregate values inside WorkPeriod:
126+
* - daysPaid
127+
* - paymentTotal
128+
* - paymentStatus
129+
*/
130+
const ActiveWorkPeriodPaymentStatuses = [
131+
WorkPeriodPaymentStatus.SCHEDULED,
132+
WorkPeriodPaymentStatus.IN_PROGRESS,
133+
WorkPeriodPaymentStatus.COMPLETED
134+
]
135+
104136
const WorkPeriodPaymentUpdateStatus = {
105137
SCHEDULED: 'scheduled',
106138
CANCELLED: 'cancelled'
@@ -126,9 +158,11 @@ module.exports = {
126158
Scopes,
127159
Interviews,
128160
ChallengeStatus,
129-
PaymentStatus,
161+
AggregatePaymentStatus,
130162
WorkPeriodPaymentStatus,
131163
WorkPeriodPaymentUpdateStatus,
132164
PaymentSchedulerStatus,
133-
PaymentProcessingSwitch
165+
PaymentProcessingSwitch,
166+
PaymentStatusRules,
167+
ActiveWorkPeriodPaymentStatuses
134168
}

src/bootstrap.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const Joi = require('joi')
33
const config = require('config')
44
const path = require('path')
55
const _ = require('lodash')
6-
const { Interviews, PaymentStatus, WorkPeriodPaymentStatus, WorkPeriodPaymentUpdateStatus, PaymentProcessingSwitch } = require('../app-constants')
6+
const { Interviews, AggregatePaymentStatus, WorkPeriodPaymentStatus, WorkPeriodPaymentUpdateStatus, PaymentProcessingSwitch } = require('../app-constants')
77
const logger = require('./common/logger')
88

99
const allowedInterviewStatuses = _.values(Interviews.Status)
@@ -17,7 +17,7 @@ Joi.resourceBookingStatus = () => Joi.string().valid('placed', 'closed', 'cancel
1717
Joi.workload = () => Joi.string().valid('full-time', 'fractional')
1818
Joi.jobCandidateStatus = () => Joi.string().valid('open', 'placed', 'selected', 'client rejected - screening', 'client rejected - interview', 'rejected - other', 'cancelled', 'interview', 'topcoder-rejected', 'applied', 'rejected-pre-screen', 'skills-test', 'skills-test', 'phone-screen', 'job-closed', 'offered')
1919
Joi.title = () => Joi.string().max(128)
20-
Joi.paymentStatus = () => Joi.string().valid(..._.values(PaymentStatus))
20+
Joi.paymentStatus = () => Joi.string().valid(..._.values(AggregatePaymentStatus))
2121
Joi.xaiTemplate = () => Joi.string().valid(...allowedXAITemplate)
2222
Joi.interviewStatus = () => Joi.string().valid(...allowedInterviewStatuses)
2323
Joi.workPeriodPaymentStatus = () => Joi.string().valid(..._.values(WorkPeriodPaymentStatus))

src/common/helper.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const models = require('../models')
2121
const eventDispatcher = require('./eventDispatcher')
2222
const busApi = require('@topcoder-platform/topcoder-bus-api-wrapper')
2323
const moment = require('moment')
24-
const { PaymentStatus, WorkPeriodPaymentStatus } = require('../../app-constants')
24+
const { PaymentStatusRules } = require('../../app-constants')
2525

2626
const localLogger = {
2727
debug: (message) =>
@@ -1829,17 +1829,8 @@ function calculateWorkPeriodPaymentStatus (workPeriod) {
18291829
}
18301830
})
18311831
}
1832-
// define rules for the payment status as constant
1833-
const PAYMENT_STATUS_RULES = [
1834-
{ paymentStatus: PaymentStatus.NO_DAYS, condition: { daysWorked: 0 } },
1835-
{ paymentStatus: PaymentStatus.IN_PROGRESS, condition: { hasWorkPeriodPaymentStatus: [WorkPeriodPaymentStatus.SCHEDULED, WorkPeriodPaymentStatus.IN_PROGRESS] } },
1836-
{ paymentStatus: PaymentStatus.COMPLETED, condition: { hasWorkPeriodPaymentStatus: [WorkPeriodPaymentStatus.COMPLETED], hasDueDays: false } },
1837-
{ paymentStatus: PaymentStatus.PARTIALLY_COMPLETED, condition: { hasWorkPeriodPaymentStatus: [WorkPeriodPaymentStatus.COMPLETED], hasDueDays: true } },
1838-
{ paymentStatus: PaymentStatus.FAILED, condition: { hasWorkPeriodPaymentStatus: [PaymentStatus.FAILED], hasDueDays: true } },
1839-
{ paymentStatus: PaymentStatus.PENDING, condition: { hasDueDays: true } }
1840-
]
18411832
// find the first rule which is matched by the Work Period
1842-
for (const rule of PAYMENT_STATUS_RULES) {
1833+
for (const rule of PaymentStatusRules) {
18431834
if (matchRule(rule)) {
18441835
return rule.paymentStatus
18451836
}

src/eventHandlers/ResourceBookingEventHandler.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const _ = require('lodash')
77
const models = require('../models')
88
const logger = require('../common/logger')
99
const helper = require('../common/helper')
10-
const { PaymentStatus } = require('../../app-constants')
10+
const { AggregatePaymentStatus } = require('../../app-constants')
1111
const JobService = require('../services/JobService')
1212
const JobCandidateService = require('../services/JobCandidateService')
1313
const WorkPeriodService = require('../services/WorkPeriodService')
@@ -296,7 +296,7 @@ async function _createWorkPeriods (periods, resourceBookingId) {
296296
startDate: period.startDate,
297297
endDate: period.endDate,
298298
daysWorked: period.daysWorked,
299-
paymentStatus: period.daysWorked === 0 ? PaymentStatus.NO_DAYS : PaymentStatus.PENDING
299+
paymentStatus: period.daysWorked === 0 ? AggregatePaymentStatus.NO_DAYS : AggregatePaymentStatus.PENDING
300300
})
301301
}
302302
}

src/eventHandlers/WorkPeriodPaymentEventHandler.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const config = require('config')
77
const models = require('../models')
88
const logger = require('../common/logger')
99
const helper = require('../common/helper')
10-
const { WorkPeriodPaymentStatus } = require('../../app-constants')
10+
const { ActiveWorkPeriodPaymentStatuses } = require('../../app-constants')
1111
const WorkPeriod = models.WorkPeriod
1212

1313
/**
@@ -25,7 +25,7 @@ async function updateWorkPeriod (payload) {
2525
data.daysPaid = 0
2626
data.paymentTotal = 0
2727
_.each(workPeriod.payments, payment => {
28-
if (_.includes([WorkPeriodPaymentStatus.SCHEDULED, WorkPeriodPaymentStatus.IN_PROGRESS, WorkPeriodPaymentStatus.COMPLETED], payment.status)) {
28+
if (_.includes(ActiveWorkPeriodPaymentStatuses, payment.status)) {
2929
data.daysPaid += payment.days
3030
data.paymentTotal += payment.amount
3131
}

src/services/ResourceBookingService.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,11 @@ async function _ensurePaidWorkPeriodsNotDeleted (resourceBookingId, oldValue, ne
171171
function _checkForPaidWorkPeriods (workPeriods) {
172172
const paidWorkPeriods = _.filter(workPeriods, workPeriod => {
173173
// filter by WP and WPP status
174-
return (workPeriod.daysPaid > 0 ||
175-
_.some(workPeriod.payments, payment => [constants.WorkPeriodPaymentStatus.COMPLETED, constants.WorkPeriodPaymentStatus.IN_PROGRESS, constants.WorkPeriodPaymentStatus.SCHEDULED].indexOf(payment.status) !== -1))
174+
return _.some(workPeriod.payments, payment => constants.ActiveWorkPeriodPaymentStatuses.indexOf(payment.status) !== -1)
176175
})
177176
if (paidWorkPeriods.length > 0) {
178-
throw new errors.BadRequestError(`WorkPeriods with id of ${_.map(paidWorkPeriods, workPeriod => workPeriod.id)}
179-
has ${constants.PaymentStatus.COMPLETED}, ${constants.PaymentStatus.PARTIALLY_COMPLETED} or ${constants.PaymentStatus.IN_PROGRESS} payment status.`)
177+
throw new errors.BadRequestError(`Can't delete associated WorkPeriods ${_.map(paidWorkPeriods, workPeriod => workPeriod.id)}
178+
as they have associated WorkPeriodsPayment with one of statuses ${constants.ActiveWorkPeriodPaymentStatuses.join(', ')}.`)
180179
}
181180
}
182181
// find related workPeriods to evaluate the changes

src/services/WorkPeriodPaymentService.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const helper = require('../common/helper')
1212
const logger = require('../common/logger')
1313
const errors = require('../common/errors')
1414
const models = require('../models')
15-
const { PaymentStatus, WorkPeriodPaymentStatus } = require('../../app-constants')
15+
const { WorkPeriodPaymentStatus } = require('../../app-constants')
1616
const { searchResourceBookings } = require('./ResourceBookingService')
1717

1818
const WorkPeriodPayment = models.WorkPeriodPayment
@@ -382,7 +382,7 @@ async function createQueryWorkPeriodPayments (currentUser, criteria) {
382382
const createdBy = await helper.getUserId(currentUser.userId)
383383
const query = criteria.query
384384
if ((typeof query['workPeriods.paymentStatus']) === 'string') {
385-
query['workPeriods.paymentStatus'] = query['workPeriods.paymentStatus'].trim().split(',').map(ps => Joi.attempt({ paymentStatus: ps.trim() }, Joi.object().keys({ paymentStatus: Joi.string().valid(PaymentStatus.PENDING, PaymentStatus.PARTIALLY_COMPLETED, PaymentStatus.FAILED) })).paymentStatus)
385+
query['workPeriods.paymentStatus'] = query['workPeriods.paymentStatus'].trim().split(',').map(ps => Joi.attempt({ paymentStatus: ps.trim() }, Joi.object().keys({ paymentStatus: Joi.paymentStatus() })).paymentStatus)
386386
}
387387
const fields = _.join(_.uniq(_.concat(
388388
['id', 'billingAccountId', 'memberRate', 'customerRate', 'workPeriods.id', 'workPeriods.resourceBookingId', 'workPeriods.daysWorked', 'workPeriods.daysPaid'],
@@ -423,7 +423,7 @@ createQueryWorkPeriodPayments.schema = Joi.object().keys({
423423
),
424424
'workPeriods.paymentStatus': Joi.alternatives(
425425
Joi.string(),
426-
Joi.array().items(Joi.string().valid(PaymentStatus.PENDING, PaymentStatus.PARTIALLY_COMPLETED, PaymentStatus.FAILED))
426+
Joi.array().items(Joi.string().valid(Joi.paymentStatus()))
427427
),
428428
'workPeriods.startDate': Joi.date().format('YYYY-MM-DD'),
429429
'workPeriods.endDate': Joi.date().format('YYYY-MM-DD'),

src/services/WorkPeriodService.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,8 @@ partiallyUpdateWorkPeriod.schema = Joi.object().keys({
310310
*/
311311
async function deleteWorkPeriod (id) {
312312
const workPeriod = await WorkPeriod.findById(id, { withPayments: true })
313-
if (_.includes([constants.PaymentStatus.COMPLETED, constants.PaymentStatus.PARTIALLY_COMPLETED, constants.PaymentStatus.IN_PROGRESS], workPeriod.paymentStatus)) {
314-
throw new errors.BadRequestError(`Can't delete WorkPeriod with paymentStatus ${constants.PaymentStatus.COMPLETED}, ${constants.PaymentStatus.PARTIALLY_COMPLETED}, or ${constants.PaymentStatus.IN_PROGRESS}`)
315-
}
316-
if (_.some(workPeriod.payments, payment => [constants.WorkPeriodPaymentStatus.COMPLETED, constants.WorkPeriodPaymentStatus.IN_PROGRESS, constants.WorkPeriodPaymentStatus.SCHEDULED].indexOf(payment.status) !== -1)) {
317-
throw new errors.BadRequestError(`Can't delete WorkPeriod if any associated WorkPeriodsPayment has status ${constants.WorkPeriodPaymentStatus.COMPLETED}, ${constants.WorkPeriodPaymentStatus.SCHEDULED} or ${constants.WorkPeriodPaymentStatus.IN_PROGRESS}`)
313+
if (_.some(workPeriod.payments, payment => constants.ActiveWorkPeriodPaymentStatuses.indexOf(payment.status) !== -1)) {
314+
throw new errors.BadRequestError(`Can't delete WorkPeriod as it has associated WorkPeriodsPayment with one of statuses ${constants.ActiveWorkPeriodPaymentStatuses.join(', ')}`)
318315
}
319316
await models.WorkPeriodPayment.destroy({
320317
where: {

test/unit/common/ResourceBookingData.js

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -842,8 +842,8 @@ const T13 = {
842842
},
843843
error: {
844844
httpStatus: 400,
845-
message: `WorkPeriods with id of 10faf505-d0e3-4d13-a817-7f1319625e91
846-
has completed, partially-completed or in-progress payment status.`
845+
message: `Can't delete associated WorkPeriods 10faf505-d0e3-4d13-a817-7f1319625e91
846+
as they have associated WorkPeriodsPayment with one of statuses scheduled, in-progress, completed.`
847847
},
848848
workPeriod: {
849849
response: [{
@@ -861,7 +861,8 @@ const T13 = {
861861
createdBy: '00000000-0000-0000-0000-000000000000',
862862
updatedBy: null,
863863
createdAt: '2021-04-10T22:25:08.289Z',
864-
updatedAt: '2021-04-10T22:25:08.289Z'
864+
updatedAt: '2021-04-10T22:25:08.289Z',
865+
payments: []
865866
},
866867
toJSON: () => T13.workPeriod.response[0].dataValues
867868
}, {
@@ -879,7 +880,23 @@ const T13 = {
879880
createdBy: '00000000-0000-0000-0000-000000000000',
880881
updatedBy: null,
881882
createdAt: '2021-04-10T22:25:08.289Z',
882-
updatedAt: '2021-04-10T22:25:08.289Z'
883+
updatedAt: '2021-04-10T22:25:08.289Z',
884+
payments: [{
885+
amount: 400,
886+
updatedBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
887+
billingAccountId: 80000071,
888+
workPeriodId: '193a029e-0d3d-48fa-a249-0a4b6b21c32a',
889+
createdAt: '2021-06-16T08:51:30.374Z',
890+
challengeId: '3c849caf-6c60-40f7-8f0e-ee72c41ede6e',
891+
memberRate: 2000,
892+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
893+
customerRate: 2600,
894+
days: 1,
895+
statusDetails: null,
896+
id: 'c3ba01c5-56db-462f-811f-65cd256096c3',
897+
status: 'in-progress',
898+
updatedAt: '2021-06-16T08:57:21.483Z'
899+
}]
883900
},
884901
toJSON: () => T13.workPeriod.response[1].dataValues
885902
}]
@@ -912,8 +929,8 @@ const T14 = {
912929
},
913930
error: {
914931
httpStatus: 400,
915-
message: `WorkPeriods with id of 10faf505-d0e3-4d13-a817-7f1319625e91
916-
has completed, partially-completed or in-progress payment status.`
932+
message: `Can't delete associated WorkPeriods 10faf505-d0e3-4d13-a817-7f1319625e91
933+
as they have associated WorkPeriodsPayment with one of statuses scheduled, in-progress, completed.`
917934
},
918935
workPeriod: {
919936
response: [{
@@ -931,7 +948,8 @@ const T14 = {
931948
createdBy: '00000000-0000-0000-0000-000000000000',
932949
updatedBy: null,
933950
createdAt: '2021-04-10T22:25:08.289Z',
934-
updatedAt: '2021-04-10T22:25:08.289Z'
951+
updatedAt: '2021-04-10T22:25:08.289Z',
952+
payments: []
935953
},
936954
toJSON: () => T14.workPeriod.response[0].dataValues
937955
}, {
@@ -949,7 +967,23 @@ const T14 = {
949967
createdBy: '00000000-0000-0000-0000-000000000000',
950968
updatedBy: null,
951969
createdAt: '2021-04-10T22:25:08.289Z',
952-
updatedAt: '2021-04-10T22:25:08.289Z'
970+
updatedAt: '2021-04-10T22:25:08.289Z',
971+
payments: [{
972+
amount: 400,
973+
updatedBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
974+
billingAccountId: 80000071,
975+
workPeriodId: '193a029e-0d3d-48fa-a249-0a4b6b21c32a',
976+
createdAt: '2021-06-16T08:51:30.374Z',
977+
challengeId: '3c849caf-6c60-40f7-8f0e-ee72c41ede6e',
978+
memberRate: 2000,
979+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
980+
customerRate: 2600,
981+
days: 1,
982+
statusDetails: null,
983+
id: 'c3ba01c5-56db-462f-811f-65cd256096c3',
984+
status: 'scheduled',
985+
updatedAt: '2021-06-16T08:57:21.483Z'
986+
}]
953987
},
954988
toJSON: () => T14.workPeriod.response[1].dataValues
955989
}]
@@ -992,7 +1026,8 @@ const T15 = {
9921026
createdBy: '00000000-0000-0000-0000-000000000000',
9931027
updatedBy: null,
9941028
createdAt: '2021-04-10T22:25:08.289Z',
995-
updatedAt: '2021-04-10T22:25:08.289Z'
1029+
updatedAt: '2021-04-10T22:25:08.289Z',
1030+
payments: []
9961031
},
9971032
toJSON: () => T15.workPeriod.response[0].dataValues
9981033
}, {
@@ -1010,7 +1045,23 @@ const T15 = {
10101045
createdBy: '00000000-0000-0000-0000-000000000000',
10111046
updatedBy: null,
10121047
createdAt: '2021-04-10T22:25:08.289Z',
1013-
updatedAt: '2021-04-10T22:25:08.289Z'
1048+
updatedAt: '2021-04-10T22:25:08.289Z',
1049+
payments: [{
1050+
amount: 400,
1051+
updatedBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1052+
billingAccountId: 80000071,
1053+
workPeriodId: '193a029e-0d3d-48fa-a249-0a4b6b21c32a',
1054+
createdAt: '2021-06-16T08:51:30.374Z',
1055+
challengeId: '3c849caf-6c60-40f7-8f0e-ee72c41ede6e',
1056+
memberRate: 2000,
1057+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1058+
customerRate: 2600,
1059+
days: 1,
1060+
statusDetails: null,
1061+
id: 'c3ba01c5-56db-462f-811f-65cd256096c3',
1062+
status: 'failed',
1063+
updatedAt: '2021-06-16T08:57:21.483Z'
1064+
}]
10141065
},
10151066
toJSON: () => T15.workPeriod.response[1].dataValues
10161067
}],
@@ -1048,8 +1099,8 @@ const T16 = {
10481099
},
10491100
error: {
10501101
httpStatus: 400,
1051-
message: `WorkPeriods with id of 10faf505-d0e3-4d13-a817-7f1319625e91
1052-
has completed, partially-completed or in-progress payment status.`
1102+
message: `Can't delete associated WorkPeriods 10faf505-d0e3-4d13-a817-7f1319625e91
1103+
as they have associated WorkPeriodsPayment with one of statuses scheduled, in-progress, completed.`
10531104
},
10541105
workPeriod: {
10551106
response: [{
@@ -1067,7 +1118,8 @@ const T16 = {
10671118
createdBy: '00000000-0000-0000-0000-000000000000',
10681119
updatedBy: null,
10691120
createdAt: '2021-04-10T22:25:08.289Z',
1070-
updatedAt: '2021-04-10T22:25:08.289Z'
1121+
updatedAt: '2021-04-10T22:25:08.289Z',
1122+
payments: []
10711123
},
10721124
toJSON: () => T16.workPeriod.response[0].dataValues
10731125
}, {
@@ -1080,12 +1132,28 @@ const T16 = {
10801132
endDate: '2021-04-17',
10811133
daysWorked: 4,
10821134
daysPaid: 4,
1083-
paymentTotal: 10.59,
1135+
paymentTotal: 400,
10841136
paymentStatus: 'completed',
10851137
createdBy: '00000000-0000-0000-0000-000000000000',
10861138
updatedBy: null,
10871139
createdAt: '2021-04-10T22:25:08.289Z',
1088-
updatedAt: '2021-04-10T22:25:08.289Z'
1140+
updatedAt: '2021-04-10T22:25:08.289Z',
1141+
payments: [{
1142+
amount: 400,
1143+
updatedBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1144+
billingAccountId: 80000071,
1145+
workPeriodId: '193a029e-0d3d-48fa-a249-0a4b6b21c32a',
1146+
createdAt: '2021-06-16T08:51:30.374Z',
1147+
challengeId: '3c849caf-6c60-40f7-8f0e-ee72c41ede6e',
1148+
memberRate: 2000,
1149+
createdBy: '57646ff9-1cd3-4d3c-88ba-eb09a395366c',
1150+
customerRate: 2600,
1151+
days: 4,
1152+
statusDetails: null,
1153+
id: 'c3ba01c5-56db-462f-811f-65cd256096c3',
1154+
status: 'completed',
1155+
updatedAt: '2021-06-16T08:57:21.483Z'
1156+
}]
10891157
},
10901158
toJSON: () => T16.workPeriod.response[1].dataValues
10911159
}]

0 commit comments

Comments
 (0)