Source: mHelpDesk/createAsset.js

/**
 * Create Asset
 * @module mHelpDesk/createAsset
 */

const uuid = require('uuid/v4')
const mysql = require('promise-mysql')
const axios = require('axios')

const { getPromiseOfAccessToken } = require('./authentication')
const config = require('../config')

/**
 * Create Asset is message 1
 * Create asset will do the following
 * - [x] Generate GUID/UUID for new asset
 * - [x] Add new asset to MHelpDesk
 * - [x] Generate Response Message (6)
 * - [x] Add Response Message to SQL table (for outgoing to send later)
 * Note that this function will log any errors and return false on error.
 * @param {Object} xmlObject
 */
const createAsset = async (xmlObject) => {
  // generate a GUID
  const guid = uuid()
  xmlObject['AssetId'] = [guid]
  console.log(`Generated UUID: ${xmlObject['AssetId'][0]}`)
  // TODO: get User Status from CyberChill for this XML message
  const xmlMessage = generateXMLMessage(xmlObject)
  const accessToken = await getPromiseOfAccessToken()

  await postEquipmentToMHelpDesk(accessToken, xmlObject)

  const connection = await mysql.createConnection(config.database)
  const sql = `INSERT INTO messages (xml, sent) VALUES (?, 0)`
  await connection.query(sql, xmlMessage)
  console.info('Inserted the following XML into database:')
  console.info(xmlMessage)
}

/**
 * Takes a key and value and returns the appropriate sanitized
 * value for that pair.
 * Cases:
 * - Lockable: Convert from 'true'/'false' string to 'y'/'n'
 * - SignageInfill/SignageDecal: Convert to *Proper Case*
 * - Hinging: Take only first letter (L/R/S)
 * @param {String} key The key from the given XML
 * @param {String} value The value given from the XML
 */
const sanitizeXMLValue = (key, value) => {
  switch (key) {
    case 'Lockable':
      // Convert from 'true'/'false' string to 'y'/'n'
      if (value !== 'true' && value !== 'false') {
        throw Error('Lockable value must be \'true\' or \'false\'')
      }
      return value === 'true' ? 'y' : 'n'
    case 'SignageInfill':
      return value
        .split(' ')
        .map(word => word.charAt(0).toUpperCase() + word.substr(1).toLowerCase())
        .join(' ')
    case 'SignageDecal':
      // Convert from 'WhaTevErCasE It Is' to 'Proper Case'
      return value
        .split(' ')
        .map(word => word.charAt(0).toUpperCase() + word.substr(1).toLowerCase())
        .join(' ')
    case 'Hinging':
      return value[0]
    default:
      return value
  }
}

/**
 * Takes the xmlObject and produces an appropriate JSON object
 * to send to the MHelpDesk API
 * @param {Object} xmlObject the object version of the recieved xml
 */
const generateJSONEquipmentFromXMLObject = xmlObject => {
  const data = {
    equipmentTypeId: config.api.fieldValues.equipmentTypeId,
    name: xmlObject['ModelNumber'][0],
    customerId: config.api.fieldValues.customerId,
    customFields: Object.entries(config.api.equipmentCustomFieldMappings)
      .map(([xmlKey, fieldId]) => {
        if (!xmlObject[xmlKey]) return null
        if (!fieldId) {
          console.error(`No value for: ${xmlKey}`)
          return null
        }
        const xmlValue = sanitizeXMLValue(xmlKey, xmlObject[xmlKey][0])
        return {
          customFieldId: fieldId,
          fieldValue: xmlValue
        }
      })
      .filter(value => value) // Remove null entries
  }
  return JSON.stringify(data)
}

/**
 * Posts the equipment JSON to the MHelpDeskAPI
 * @param {String} accessToken JWT Access Token for MHelpDesk
 * @param {Object} xmlObject the object version of the recieved xml
 */
const postEquipmentToMHelpDesk = async (accessToken, xmlObject) => {
  const jsonEquipment = generateJSONEquipmentFromXMLObject(xmlObject)
  console.log(jsonEquipment)
  const response = await axios({
    url: `${config.api.url}/portal/${config.api.portalId}/equipment`,
    method: 'post',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    data: jsonEquipment
  })
  console.log(response)
  return response
}

/**
 * This function will return an UpdateAsset Message (6).
 * This should be sent to Parmalat upon successful creation of an MHelpDesk
 * Object.
 * @param {Object} xmlObject
 * @return {String} An UpdateAssetMessage
 */
const generateXMLMessage = (xmlObject) => {
  if (!xmlObject) throw new Error('xmlObject is null')
  if (!xmlObject['ClientReferenceNumber'] ||
    !xmlObject['AssetId'] ||
    !xmlObject['ClientTag'] ||
    !xmlObject['SerialNumber'] ||
    !xmlObject['Grade']) throw new Error('Missing Key')

  return `<?xml version="1.0" encoding="UTF-8"?>
<ns0:UpdateAsset xmlns:ns0="urn:parmalat.com.au:sales:Refrigeration">
  <ClientReferenceNumber>${xmlObject['ClientReferenceNumber']}</ClientReferenceNumber>
  <AssetId>${xmlObject['AssetId']}</AssetId>
  <ClientTag>${xmlObject['ClientTag']}</ClientTag>
  <SerialNumber>${xmlObject['SerialNumber']}</SerialNumber>
  <GradeRange>${xmlObject['Grade']}</GradeRange>
  <User_Status>ACTV</User_Status>
</ns0:UpdateAsset>`
}

exports.createAsset = createAsset

exports.generateXMLMessage = generateXMLMessage
exports.generateJSONEquipmentFromXMLObject = generateJSONEquipmentFromXMLObject
exports.sanitizeXMLValue = sanitizeXMLValue