private FrontLineWorker processInstance(Map<String, Object> record, State state) {
    String mctsFlwId = (String) record.get(ID);
    Long contactNumber = (Long) record.get(CONTACT_NO);
    String name = (String) record.get(NAME);
    Long districtId = (Long) record.get(DISTRICT_ID);
    District district = getDistrictById(state, districtId);

    FrontLineWorker instance = new FrontLineWorker(contactNumber);
    instance.setMctsFlwId(mctsFlwId);
    instance.setName(name);
    instance.setDistrict(district);
    if (null != district) {
      instance.setLanguage(district.getLanguage());
    }
    return instance;
  }
  /**
   * 2.2.7 Set User Language Location Code API IVR shall invoke this API to provide user
   * languageLocation preference to MoTech. /api/mobileacademy/languageLocationCode
   *
   * <p>3.2.3 Set User Language Location Code API IVR shall invoke this API to set the language
   * location code of the user in NMS database. /api/mobilekunji/languageLocationCode
   */
  @RequestMapping(
      value = "/{serviceName}/languageLocationCode", // NO CHECKSTYLE Cyclomatic Complexity
      method = RequestMethod.POST,
      headers = {"Content-type=application/json"})
  @ResponseStatus(HttpStatus.OK)
  @Transactional
  public void setUserLanguageLocationCode(
      @PathVariable String serviceName, @RequestBody UserLanguageRequest userLanguageRequest) {

    log(
        String.format("REQUEST: /%s/languageLocationCode (POST)", serviceName),
        LogHelper.nullOrString(userLanguageRequest));

    Long callingNumber = userLanguageRequest.getCallingNumber();
    Long callId = userLanguageRequest.getCallId();
    String languageLocationCode = userLanguageRequest.getLanguageLocationCode();

    StringBuilder failureReasons = validate(callingNumber, callId);
    validateFieldPresent(
        failureReasons, LANGUAGE_LOCATION_CODE, userLanguageRequest.getLanguageLocationCode());

    if (!(MOBILE_ACADEMY.equals(serviceName) || MOBILE_KUNJI.equals(serviceName))) {
      failureReasons.append(String.format(INVALID, SERVICE_NAME));
    }

    Service service = null;

    service = getServiceFromName(serviceName);

    if (failureReasons.length() > 0) {
      throw new IllegalArgumentException(failureReasons.toString());
    }

    FrontLineWorker flw = frontLineWorkerService.getByContactNumber(callingNumber);
    if (flw == null) {
      flw = new FrontLineWorker(callingNumber);
    }

    Language language = languageService.getForCode(languageLocationCode);
    if (null == language) {
      throw new NotFoundException(String.format(NOT_FOUND, LANGUAGE_LOCATION_CODE));
    }

    flw.setLanguage(language);

    State state = getStateForFrontLineWorker(flw, null);

    if (!serviceDeployedInUserState(service, state)) {
      throw new NotDeployedException(String.format(NOT_DEPLOYED, service));
    }

    if (!frontLineWorkerAuthorizedForAccess(flw, state)) {
      throw new NotAuthorizedException(String.format(NOT_AUTHORIZED, CALLING_NUMBER));
    }

    // MOTECH-1667 added to get an upsert method included
    if (flw.getId() == null) {
      frontLineWorkerService.add(flw);
    } else {
      frontLineWorkerService.update(flw);
    }
  }
  /**
   * 2.2.6 Save CallDetails API IVR shall invoke this API to send MA call details to MoTech.
   * /api/mobileacademy/callDetails
   *
   * <p>3.2.2 Save Call Details API This API enables IVR to send call details to NMS_MoTech_MK. This
   * data is further saved in NMS database and used for reporting purpose.
   * /api/mobilekunji/callDetails
   */
  @RequestMapping(
      value = "/{serviceName}/callDetails",
      method = RequestMethod.POST,
      headers = {"Content-type=application/json"})
  @ResponseStatus(HttpStatus.OK)
  @Transactional
  public void saveCallDetails(
      @PathVariable String serviceName,
      @RequestBody CallDetailRecordRequest callDetailRecordRequest) {
    Service service = null;
    StringBuilder failureReasons;

    if (!(MOBILE_ACADEMY.equals(serviceName) || MOBILE_KUNJI.equals(serviceName))) {
      throw new IllegalArgumentException(String.format(INVALID, "serviceName"));
    }

    failureReasons =
        validate(
            callDetailRecordRequest.getCallingNumber(),
            callDetailRecordRequest.getCallId(),
            callDetailRecordRequest.getOperator(),
            callDetailRecordRequest.getCircle());

    // Verify common elements
    // (callStartTime, callEndTime, callDurationInPulses, endOfUsagePromptCount, callStatus,
    // callDisconnectReason)
    failureReasons.append(validateCallDetailsCommonElements(callDetailRecordRequest));

    if (MOBILE_ACADEMY.equals(serviceName)) {
      service = Service.MOBILE_ACADEMY;
    }

    if (MOBILE_KUNJI.equals(serviceName)) {
      service = Service.MOBILE_KUNJI;

      // Verify MK elements (welcomeMessagePromptFlag)
      failureReasons.append(validateCallDetailsMobileKunjiElements(callDetailRecordRequest));
    }

    for (CallContentRequest callContentRequest : callDetailRecordRequest.getContent()) {
      failureReasons.append(validateCallContentRequest(service, callContentRequest));
    }

    if (failureReasons.length() > 0) {
      throw new IllegalArgumentException(failureReasons.toString());
    }

    FrontLineWorker flw =
        frontLineWorkerService.getByContactNumber(callDetailRecordRequest.getCallingNumber());
    if (null == flw) {
      throw new NotFoundException(String.format(NOT_FOUND, "callingNumber"));
    }

    createCallDetailRecord(flw, callDetailRecordRequest, service);

    // if this is the FLW's first time calling the service, set her status to ACTIVE
    if (flw.getStatus() == FrontLineWorkerStatus.INACTIVE) {
      flw.setStatus(FrontLineWorkerStatus.ACTIVE);
      frontLineWorkerService.update(flw);
    }
  }