Implementation details
The implementation of this callout requires a custom outbound class and API endpoint. The
outbound class facilitates outbound requests from WFM to the custom service used for
Mobile Shift Offer. This class must implement the
ShiftOfferCalloutService
interface. To enable the callout, the
outbound class is added to the SHIFT_OFFER_SVC registry parameter,
using the bean ID for the class.
The outbound class is responsible for implementing this functionality:
- Communicating shift offers from WFM to the custom service
- Communicating shift offer cancellations to the custom service (optional)
See "SHIFT_OFFER_SVC" in the Infor Workforce Management Registry Parameter Reference Guide.
The API endpoint facilitates inbound requests from the custom service to complete Mobile
Shift Offer transactions. The endpoint must call the
ShiftOfferCallbackHandlerService
API, which manages Mobile Shift
Offer transactions in the database, to complete transactions. Customers implementing
this callout must work with Infor Consulting Services to develop the required API
endpoint. All custom API code must follow the required ISO processes and undergo a
security scan.
The API endpoint is responsible for implementing this functionality:
- Receiving employee claim requests and assigning offered shifts to the claiming employees, including assignment validations
- Expiring shift offers that have timed out
- Receiving employee shift rejection decisions from employee and communicating them back to WFM (optional)
Offering shifts
ShiftOfferCDOData
object as input data
from WFM when a user offers one or more shifts in the scheduling screens. This
object contains data related to the Mobile Shift Offer transaction. These objects
are included in this object:Object | Description |
---|---|
module | Identifies if shifts being offered were created in MVS or LFSO. |
empIds | Contains the employee IDs for the employees that the shifts are being offered to. |
shiftOfferShifts | Contains a list of the shifts being offered in the transaction and data about each shift. |
shiftOffer | Contains these details about the shift offer transaction:
|
The outbound class is responsible for passing shift offers from WFM to the custom service. The custom service can use any supported method to communicate the offered shifts to the selected employees. For each shift offered, the outbound class must output an external code that is used to identify the shift.
ShiftOfferCalloutServiceImplJDA
implementation uses this function to send the shift data and a list of employees'
contact information, or empChannels
, to the JDA service. This
implementation outputs the response code from JDA as the external code used to
identify the
shift.private fun sendShiftToBroadcastingPlatform(
offer: ShiftOfferCDOData,
empChannels: Map<Long, EmployeeShiftOfferChannel>,
callbackUrl: String
): Map<Long, String> {
val unassignedShiftIdToExtCode = HashMap<Long, String>()
val offerWindow: Int? = offer.shiftOffer?.shiftOfferDurationInMin
if (offerWindow == null) {
logger.error("Skipping sendShiftToBroadcastingPlatform, expected non-null shift offer from core")
return unassignedShiftIdToExtCode
}
for (shift in offer.shiftOfferShifts) {
if (shift.unassignedShift?.unasgnShiftId == null) {
logger.error("Skipping shift, expected non-null unassignedShift with non-null ID from core code")
continue
}
val shiftexShiftId: String = sendShift(offer.empIds, shift.unassignedShift, offerWindow, callbackUrl, empChannels)
unassignedShiftIdToExtCode[shift.unassignedShift.unasgnShiftId] = shiftexShiftId
if (logger.isDebugEnabled) {
logger.debug("offer shift: ${shift.unassignedShift}\n to JDA and received external code: $shiftexShiftId")
}
}
return unassignedShiftIdToExtCode
}
The outbound class can validate if employees are eligible to receive shift offers
using the method getNoChannelEmployees
. The method returns a list
of employee IDs for employees that can receive a shift offer. This method also
returns a list of employee names that cannot receive shift offers. A soft-stop
message is displayed to the user that initiated the shift offer transaction if one
or more selected employees are not eligible to receive shift offers. If no employees
can receive a shift offer, the transaction is not allowed, and a validation message
is displayed.
For example, the default ShiftOfferCalloutServiceImplJDA
implementation places employees that have at least one contact method specified in
their employee profile in the list of employees that can receive shift offers.
Employees that do not have any contact methods are placed in the list of employees
that cannot receive shift offers.
override fun getNoChannelEmployees(input: ShiftOfferInputData.SocGetNoChannelEmployeesInput): ShiftOfferOutputData.SocGetNoChannelEmployeesOutput {
val finalEmpIds: MutableList<Long> = ArrayList()
val empNames: MutableList<EmpName> = mutableListOf()
for (empId in input.offer.empIds) {
val empShiftOfferChannels = this.getEmployeeShiftOfferChannels(empId)
if (empShiftOfferChannels.channelValues.isNullOrEmpty()) {
val emp = employeeService.getEmployeeById(empId)
empNames.add(EmpName(emp.empLastname, emp.empFirstname))
} else {
finalEmpIds.add(empId)
}
}
empNames.sort()
val empNameStsList: MutableList<String> = ArrayList(empNames.size)
for (empName in empNames) {
empNameStsList.add(empName.lastName + ", " + empName.firstName)
}
return ShiftOfferOutputData.SocGetNoChannelEmployeesOutput(empNameStsList, finalEmpIds)
}
private fun getEmployeeShiftOfferChannels(empId: Long): EmployeeShiftOfferChannel {
val chnlValueMap: MutableMap<SchShiftOfferChannel, String> = mutableMapOf()
chnlValueMap.putAll(populateEmpChannelValue(empId, JDAShiftOfferChannel.EMAIL))
chnlValueMap.putAll(populateEmpChannelValue(empId, JDAShiftOfferChannel.SMS))
chnlValueMap.putAll(populateEmpChannelValue(empId, JDAShiftOfferChannel.IVR))
val channel = EmployeeShiftOfferChannel()
channel.empId = empId
channel.channelValues = chnlValueMap
return channel
}
Assigning claimed shifts
Employees who are selected in a shift offer transaction can claim the offered shift. The mechanism that employees can use to claim shifts, such as a link in an email message, is handled by the custom service. The custom service must send claim requests to the custom API endpoint. The API endpoint is responsible for assigning the shift to the claiming employees, including handling any associated validations.
Expiring shift offers
Users specify an offer window when they initiate a shift offer. This determines the number of minutes after the shift offer when employees can claim the shift. The outbound class may provide the specified offer window to the custom service to indicate when it should expire the shift offer. When shift offers expire, the custom service can send a request to the custom API endpoint. The API endpoint is responsible for expiring the shift offer.
Shift expiry is optional in cases where shift offer expiry is not supported by the service provider. In those cases, the API endpoint must validate shift claims to ensure that shifts that are claimed after the shift's start time are not assigned to claiming employees.
Recording employee rejections
Employees may reject a shift offer, depending on the options supported by the custom service provider. The custom service can send a request for employee rejections to the custom API endpoint. The API endpoint can record the rejections or perform other functions, depending on the customer requirements. Handling employee rejections is optional.
Canceling shift offers
The outbound class receives a SocCancelInput
object as an input from
WFM when a user cancels an existing shift offer in the scheduling screens. This
object includes the external code used to identify the shift. The outbound class
determines what to do when shift offers are canceled.
ShiftOfferCalloutServiceImplJDA
implementation sends the shift offer cancellation to the JDA service using the
external code and checks the response for
errors.override fun cancelShiftOffer(input: ShiftOfferInputData.SocCancelInput): ShiftOfferOutputData.SocCancelOutput {
val stub = getShiftexServiceStub()
val cancelShft = CancelShiftReq()
cancelShft.shiftId = input.externalCode
val response = stub.cancelShift(cancelShft)
if (!MSG_OK.equals(response.errorCode, ignoreCase = true)) {
var errorCode = response.errorCode
errorCode = FileUtil.preventPathTraversal(errorCode)
errorCode = Encode.forHtml(errorCode)
logger.debug("CancelShiftResp : ")
logger.debug("error code : $errorCode")
throw WBException("Shiftex error occurred when canceling shift: $errorCode")
}
return ShiftOfferOutputData.SocCancelOutput()
}
Shift offer cancellation is an optional feature. If your implementation does not support shift offer cancellations, it is recommended to hide the
buttons in the scheduling screens using security group settings.