feat(api): add staff order detail and compliance eligibility

This commit is contained in:
zouantchaw
2026-03-19 20:17:48 +01:00
parent 4d74fa52ab
commit d2bcb9f3ba
18 changed files with 1051 additions and 42 deletions

View File

@@ -160,6 +160,22 @@ async function finalizeVerifiedUpload({
};
}
async function approveVerification({
token,
verificationId,
note = 'Smoke approval',
}) {
return apiCall(`/verifications/${verificationId}/review`, {
method: 'POST',
token,
body: {
decision: 'APPROVED',
note,
reasonCode: 'SMOKE_APPROVAL',
},
});
}
async function signInClient() {
return apiCall('/auth/client/sign-in', {
method: 'POST',
@@ -794,6 +810,8 @@ async function main() {
assert.equal(typeof assignedTodayShift.longitude, 'number');
assert.equal(assignedTodayShift.clockInMode, fixture.shifts.assigned.clockInMode);
assert.equal(assignedTodayShift.allowClockInOverride, fixture.shifts.assigned.allowClockInOverride);
const clockableTodayShift = todaysShifts.items.find((shift) => shift.attendanceStatus === 'NOT_CLOCKED_IN')
|| assignedTodayShift;
logStep('staff.clock-in.shifts-today.ok', { count: todaysShifts.items.length });
const attendanceStatusBefore = await apiCall('/staff/clock-in/status', {
@@ -827,30 +845,61 @@ async function main() {
const availableOrders = await apiCall('/staff/orders/available?limit=20', {
token: staffAuth.idToken,
});
const availableOrder = availableOrders.items.find((item) => item.orderId === createdRecurringOrder.orderId)
|| availableOrders.items[0];
assert.ok(availableOrder);
assert.ok(availableOrder.roleId);
logStep('staff.orders.available.ok', { count: availableOrders.items.length, orderId: availableOrder.orderId });
assert.ok(availableOrders.items.length > 0);
const bookedOrder = await apiCall(`/staff/orders/${availableOrder.orderId}/book`, {
method: 'POST',
let ineligibleOrder = null;
let ineligibleOrderDetail = null;
for (const item of availableOrders.items) {
const detail = await apiCall(`/staff/orders/${item.orderId}`, {
token: staffAuth.idToken,
});
if (!ineligibleOrderDetail && detail.eligibility?.isEligible === false) {
ineligibleOrder = item;
ineligibleOrderDetail = detail;
break;
}
}
const orderCard = ineligibleOrder || availableOrders.items[0];
const orderDetail = ineligibleOrderDetail || await apiCall(`/staff/orders/${orderCard.orderId}`, {
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-order-book'),
body: {
roleId: availableOrder.roleId,
},
});
assert.equal(bookedOrder.orderId, availableOrder.orderId);
assert.ok(bookedOrder.assignedShiftCount >= 1);
assert.equal(bookedOrder.status, 'PENDING');
assert.ok(Array.isArray(bookedOrder.assignedShifts));
logStep('staff.orders.book.ok', {
orderId: bookedOrder.orderId,
assignedShiftCount: bookedOrder.assignedShiftCount,
status: bookedOrder.status,
assert.ok(orderCard.roleId);
logStep('staff.orders.available.ok', { count: availableOrders.items.length, orderId: orderCard.orderId });
assert.equal(orderDetail.orderId, orderCard.orderId);
assert.equal(orderDetail.roleId, orderCard.roleId);
assert.ok(orderDetail.clientName);
assert.ok(orderDetail.schedule);
assert.ok(orderDetail.location);
assert.ok(Array.isArray(orderDetail.managers));
assert.ok(orderDetail.eligibility);
logStep('staff.orders.detail.ok', {
orderId: orderDetail.orderId,
status: orderDetail.status,
isEligible: orderDetail.eligibility.isEligible,
});
if (orderDetail.eligibility?.isEligible === false) {
const rejectedIneligibleBooking = await apiCall(`/staff/orders/${orderCard.orderId}/book`, {
method: 'POST',
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-order-book-ineligible'),
body: {
roleId: orderDetail.roleId,
},
allowFailure: true,
});
assert.equal(rejectedIneligibleBooking.statusCode, 422);
assert.equal(rejectedIneligibleBooking.body.code, 'UNPROCESSABLE_ENTITY');
assert.ok(Array.isArray(rejectedIneligibleBooking.body.details?.blockers));
logStep('staff.orders.book.ineligible.rejected.ok', {
orderId: orderCard.orderId,
blockers: rejectedIneligibleBooking.body.details.blockers.length,
});
}
const openShifts = await apiCall('/staff/shifts/open', {
token: staffAuth.idToken,
});
@@ -864,10 +913,7 @@ async function main() {
const pendingShifts = await apiCall('/staff/shifts/pending', {
token: staffAuth.idToken,
});
assert.ok(
bookedOrder.assignedShifts.some((shift) => pendingShifts.items.some((item) => item.shiftId === shift.shiftId))
);
const pendingShift = pendingShifts.items.find((item) => item.shiftId === fixture.shifts.available.id)
const pendingShift = pendingShifts.items.find((item) => item.shiftId === openShift.shiftId)
|| pendingShifts.items[0];
assert.ok(pendingShift);
logStep('staff.shifts.pending.ok', { count: pendingShifts.items.length });
@@ -1146,12 +1192,12 @@ async function main() {
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-shift-apply'),
body: {
roleId: fixture.shiftRoles.availableBarista.id,
roleId: openShift.roleId,
},
});
logStep('staff.shifts.apply.ok', appliedShift);
const acceptedShift = await apiCall(`/staff/shifts/${fixture.shifts.assigned.id}/accept`, {
const acceptedShift = await apiCall(`/staff/shifts/${pendingShift.shiftId}/accept`, {
method: 'POST',
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-shift-accept'),
@@ -1164,7 +1210,7 @@ async function main() {
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-clock-in'),
body: {
shiftId: fixture.shifts.assigned.id,
shiftId: clockableTodayShift.shiftId,
sourceType: 'GEO',
deviceId: 'smoke-iphone-15-pro',
latitude: fixture.clockPoint.latitude + 0.0075,
@@ -1177,7 +1223,7 @@ async function main() {
},
});
assert.equal(clockIn.validationStatus, 'FLAGGED');
assert.equal(clockIn.effectiveClockInMode, fixture.shifts.assigned.clockInMode);
assert.equal(clockIn.effectiveClockInMode, clockableTodayShift.clockInMode);
assert.equal(clockIn.overrideUsed, true);
assert.ok(clockIn.securityProofId);
logStep('staff.clock-in.ok', clockIn);
@@ -1187,7 +1233,7 @@ async function main() {
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-clock-in-duplicate'),
body: {
shiftId: fixture.shifts.assigned.id,
shiftId: clockableTodayShift.shiftId,
sourceType: 'GEO',
deviceId: 'smoke-iphone-15-pro',
latitude: fixture.clockPoint.latitude,
@@ -1214,7 +1260,7 @@ async function main() {
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-location-stream'),
body: {
shiftId: fixture.shifts.assigned.id,
shiftId: clockableTodayShift.shiftId,
sourceType: 'GEO',
deviceId: 'smoke-iphone-15-pro',
points: [
@@ -1268,7 +1314,7 @@ async function main() {
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-clock-out'),
body: {
shiftId: fixture.shifts.assigned.id,
shiftId: clockableTodayShift.shiftId,
sourceType: 'GEO',
deviceId: 'smoke-iphone-15-pro',
latitude: fixture.clockPoint.latitude,
@@ -1283,7 +1329,7 @@ async function main() {
assert.ok(clockOut.securityProofId);
logStep('staff.clock-out.ok', clockOut);
const submittedCompletedShift = await apiCall(`/staff/shifts/${fixture.shifts.assigned.id}/submit-for-approval`, {
const submittedCompletedShift = await apiCall(`/staff/shifts/${clockableTodayShift.shiftId}/submit-for-approval`, {
method: 'POST',
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-shift-submit-approval'),
@@ -1430,6 +1476,50 @@ async function main() {
assert.equal(uploadedGovId.finalized.documentId, fixture.documents.governmentId.id);
logStep('staff.profile.document.upload.ok', uploadedGovId.finalized);
if (!['APPROVED', 'AUTO_PASS'].includes(`${uploadedGovId.finalized.verification?.status || ''}`)) {
const reviewedGovId = await approveVerification({
token: ownerSession.sessionToken,
verificationId: uploadedGovId.finalized.verification.verificationId,
note: 'Smoke approval for government ID',
});
assert.equal(reviewedGovId.status, 'APPROVED');
logStep('staff.profile.document.review.ok', {
verificationId: reviewedGovId.verificationId,
status: reviewedGovId.status,
});
}
const uploadedI9 = await finalizeVerifiedUpload({
token: staffAuth.idToken,
uploadCategory: 'staff-tax-form',
filename: 'i9-completed.pdf',
contentType: 'application/pdf',
content: Buffer.from('fake-i9-tax-form'),
finalizePath: `/staff/profile/documents/${fixture.documents.taxFormI9.id}/upload`,
finalizeMethod: 'PUT',
verificationType: 'tax_form',
subjectId: fixture.documents.taxFormI9.id,
rules: {
documentId: fixture.documents.taxFormI9.id,
formType: 'I-9',
},
});
assert.equal(uploadedI9.finalized.documentId, fixture.documents.taxFormI9.id);
logStep('staff.profile.tax-form.upload.ok', uploadedI9.finalized);
if (!['APPROVED', 'AUTO_PASS'].includes(`${uploadedI9.finalized.verification?.status || ''}`)) {
const reviewedI9 = await approveVerification({
token: ownerSession.sessionToken,
verificationId: uploadedI9.finalized.verification.verificationId,
note: 'Smoke approval for completed I-9',
});
assert.equal(reviewedI9.status, 'APPROVED');
logStep('staff.profile.tax-form.review.ok', {
verificationId: reviewedI9.verificationId,
status: reviewedI9.status,
});
}
const uploadedAttire = await finalizeVerifiedUpload({
token: staffAuth.idToken,
uploadCategory: 'staff-attire',
@@ -1474,9 +1564,57 @@ async function main() {
const profileDocumentsAfter = await apiCall('/staff/profile/documents', {
token: staffAuth.idToken,
});
assert.ok(profileDocumentsAfter.items.some((item) => item.documentId === fixture.documents.governmentId.id));
const governmentIdAfter = profileDocumentsAfter.items.find((item) => item.documentId === fixture.documents.governmentId.id);
assert.ok(governmentIdAfter);
assert.equal(governmentIdAfter.status, 'VERIFIED');
logStep('staff.profile.documents-after.ok', { count: profileDocumentsAfter.items.length });
const availableOrdersAfterVerification = await apiCall('/staff/orders/available?limit=20', {
token: staffAuth.idToken,
});
let eligibleOrder = null;
let eligibleOrderDetail = null;
for (const item of availableOrdersAfterVerification.items) {
const detail = await apiCall(`/staff/orders/${item.orderId}`, {
token: staffAuth.idToken,
});
if (detail.eligibility?.isEligible === true) {
eligibleOrder = item;
eligibleOrderDetail = detail;
break;
}
}
assert.ok(eligibleOrder, 'Expected at least one eligible available order after document verification');
const bookedOrder = await apiCall(`/staff/orders/${eligibleOrder.orderId}/book`, {
method: 'POST',
token: staffAuth.idToken,
idempotencyKey: uniqueKey('staff-order-book'),
body: {
roleId: eligibleOrderDetail.roleId,
},
});
assert.equal(bookedOrder.orderId, eligibleOrder.orderId);
assert.ok(bookedOrder.assignedShiftCount >= 1);
assert.equal(bookedOrder.status, 'PENDING');
assert.ok(Array.isArray(bookedOrder.assignedShifts));
logStep('staff.orders.book.ok', {
orderId: bookedOrder.orderId,
assignedShiftCount: bookedOrder.assignedShiftCount,
status: bookedOrder.status,
});
const pendingShiftsAfterBooking = await apiCall('/staff/shifts/pending', {
token: staffAuth.idToken,
});
assert.ok(
bookedOrder.assignedShifts.some((shift) => pendingShiftsAfterBooking.items.some((item) => item.shiftId === shift.shiftId))
);
logStep('staff.shifts.pending-after-order-book.ok', {
count: pendingShiftsAfterBooking.items.length,
bookedShiftCount: bookedOrder.assignedShiftCount,
});
const certificatesAfter = await apiCall('/staff/profile/certificates', {
token: staffAuth.idToken,
});