// @ts-check const { log } = require('cozy-konnector-libs') const moment = require('moment') const Sentry = require('@sentry/node') /** * Return User PDL * @param {string} result * @returns {string} */ function parseUserPdl(result) { log('info', 'Parsing User Pdl') const json = JSON.stringify(result) return JSON.parse(json)['Envelope']['Body']['rechercherPointResponse'][ 'points' ]['point']['$'].id } /** * Return User address * @param {string} result * @returns {Address} */ function parseUserAddress(result) { log('info', 'Parsing user Address') const json = JSON.stringify(result) return JSON.parse(json)['Envelope']['Body'][ 'consulterDonneesTechniquesContractuellesResponse' ]['point']['donneesGenerales']['adresseInstallation'] } /** * Return User off-peak hours * @param {string} result * @returns {string} * @example "3H00-8H00;13H30-16H30" */ function parseUserOffPeakHours(result) { log('info', 'Parsing user off-peak hours') const json = JSON.stringify(result) const rawOffPeakHours = JSON.parse(json)['Envelope']['Body'][ 'consulterDonneesTechniquesContractuellesResponse' ]['point']['situationComptage']['dispositifComptage']['relais'][ 'plageHeuresCreuses' ] // extract off-peak hours from parentheses let match = rawOffPeakHours.match(/\((.*?)\)/) // Check if there is a match and return the content if (match) { return match[1] } else { throw new Error('invalid off-peak hours format') } } /** * Return User contract start date * @param {string} result * @returns {Contract[] | Contract} */ function parseContracts(result) { log('info', 'Parsing contract') const json = JSON.stringify(result) return JSON.parse(json)['Envelope']['Body'][ 'rechercherServicesSouscritsMesuresResponse' ]['servicesSouscritsMesures']['serviceSouscritMesures'] } /** * Return User contract start date * @param {string} result * @returns {number} */ function parseServiceId(result) { log('info', 'Parsing serviceId') const json = JSON.stringify(result) return JSON.parse(json)['Envelope']['Body'][ 'commanderCollectePublicationMesuresResponse' ]['serviceSouscritId'] } /** * Parsing SGE xml reply to get only mesure data * @param {string} result * @returns {SGEData[]} */ function parseSgeXmlData(result) { log('info', 'Parsing list of documents') const json = JSON.stringify(result) return JSON.parse(json)['Envelope']['Body'][ 'consulterMesuresDetailleesResponseV3' ]['grandeur']['points'] } /** * Format data for DB storage * @param {SGEData[]} data * @returns {Promise<EnedisKonnectorData[]>} Parsed timestamp array */ async function formateDataForDoctype(data) { log('info', 'Formatting data') return data.map(record => { const date = moment(record.d, 'YYYY/MM/DD h:mm:ss') return { year: parseInt(date.format('YYYY')), month: parseInt(date.format('M')), day: parseInt(date.format('D')), hour: parseInt(date.format('H')), minute: parseInt(date.format('m')), load: record.v, } }) } /** * Check if response contains contracts * @param {string} parsedReply * @return {boolean} */ function checkContractExists(parsedReply) { const json = JSON.stringify(parsedReply) return JSON.parse(json)['Envelope']['Body'][ 'rechercherServicesSouscritsMesuresResponse' ]['servicesSouscritsMesures'] } /** * Format tag in order to be manipulated easily * @param {string} name * @returns {string} name */ function parseTags(name) { if (name.split(':')[1] !== undefined) { return name.split(':')[1] } return name } /** * * @param {string} value * @param {string} name * @returns {string|number} value */ function parseValue(value, name) { // Wh => KWh if (name === 'v') { return parseFloat((parseInt(value) / 1000).toFixed(2)) } return value } /** * * @param {string} value * @param {string} name * @returns {string|number} value */ function parseValueHalfHour(value, name) { // W * 1/2h => KW * h if (name === 'v') { return parseFloat((parseInt(value) / 2000).toFixed(2)) } return value } /** * Remove SGE useless multiple white spaces * @param {string} str * @returns {string} */ function removeMultipleSpaces(str) { return str.replace(/ +/g, ' ') } /** * Remove SGE useless dots * This regular expression matches one or more consecutive dots * and then in the replacement function, it checks if the dots are surrounded by non-dot characters. * If so, it replaces them with a space; otherwise, it removes them * @example * console.log(removeDots(".....03G2")); // Outputs: "03G2" * console.log(removeDots("....ETG..4...D")); // Outputs: "ETG 4 D" * console.log(removeDots("ETG 4 D")); // Outputs: "ETG 4 D" * @param {string} input - The input string containing dots to be removed. * @returns {string} The input string without dots. */ function removeDots(input) { return input.replace(/\.+/g, (match, offset, string) => { if ( offset > 0 && offset < string.length - match.length && string[offset - 1] !== '.' && string[offset + match.length] !== '.' ) { return ' ' } return '' }) } /** * Remove SGE address number * @param {string} str * @returns {string} */ function removeAddressNumber(str) { return str.replace(/\d+ |b |B |T |t |\d+/g, '') } /** * Parse PDL and to validate correct length of 14 digits * @param {number} pointId - some pdl start with 0 * @returns {string} pointId with 14 digits * @example "07123456789012" */ function parsePointId(pointId) { const strPointId = pointId.toString() if (strPointId.length === 14) { return strPointId } else if (strPointId.length === 13) { return `0${strPointId}` } else { const errorMessage = 'PointId is malformed' Sentry.captureException(errorMessage, { tags: { section: 'parsePointId', }, extra: { pointId: pointId, }, }) throw new Error(errorMessage) } } module.exports = { checkContractExists, formateDataForDoctype, parseContracts, parsePointId, parseServiceId, parseSgeXmlData, parseTags, parseUserAddress, parseUserOffPeakHours, parseUserPdl, parseValue, parseValueHalfHour, removeAddressNumber, removeMultipleSpaces, removeDots, }