From e193507b762b97394692b5a1baaff338c956de62 Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Mon, 3 Oct 2022 18:38:07 +0200 Subject: [PATCH] feat(rechercherpoint): add two fallback in case of no rechercher point match --- src/core/findUserAddress.js | 54 ++++++++++++++++++++++++++++++++++ src/core/findUserPdl.js | 13 ++++++-- src/core/index.js | 2 ++ src/core/types/types.js | 16 ++++++++++ src/core/verifyUserIdentity.js | 50 ++++++++++++++++++++++++++++++- src/helpers/parsing.js | 33 +++++++++++++++++++++ src/requests/sge.js | 43 ++++++++++++++++++++++++--- 7 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 src/core/findUserAddress.js diff --git a/src/core/findUserAddress.js b/src/core/findUserAddress.js new file mode 100644 index 0000000..a4124fd --- /dev/null +++ b/src/core/findUserAddress.js @@ -0,0 +1,54 @@ +// @ts-check +const { log, errors } = require('cozy-konnector-libs') +const soapRequest = require('easy-soap-request') +const { + parseTags, + parseValue, + parseUserAddress, +} = require('../helpers/parsing') +const xml2js = require('xml2js') +const { consulterDonneesTechniquesContractuelles } = require('../requests/sge') + +/** + * Get user contract start date + * @param {string} url + * @param {string} apiAuthKey + * @param {string} userLogin + * @param {number} pointId + * @returns {Promise<Address>} + */ +async function findUserAddress(url, apiAuthKey, userLogin, pointId) { + log('info', 'Fetching user address') + const sgeHeaders = { + 'Content-Type': 'text/xml;charset=UTF-8', + apikey: apiAuthKey, + } + + const { response } = await soapRequest({ + url: `${url}/enedis_SGE_ConsultationDonneesTechniquesContractuelles/1.0`, + headers: sgeHeaders, + xml: consulterDonneesTechniquesContractuelles(pointId, userLogin, false), + }).catch(err => { + log('error', 'Error while fetching user : ' + err) + throw errors.VENDOR_DOWN + }) + + const result = await xml2js.parseStringPromise(response.body, { + tagNameProcessors: [parseTags], + valueProcessors: [parseValue], + explicitArray: false, + }) + + try { + return parseUserAddress(result) + } catch (error) { + log('error', 'Error while processing user address: ' + error) + log( + 'error', + `Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}` + ) + throw errors.NOT_EXISTING_DIRECTORY + } +} + +module.exports = { findUserAddress } diff --git a/src/core/findUserPdl.js b/src/core/findUserPdl.js index b522561..318d955 100644 --- a/src/core/findUserPdl.js +++ b/src/core/findUserPdl.js @@ -22,7 +22,8 @@ async function findUserPdl( name, address, postalCode, - inseeCode + inseeCode, + escalierEtEtageEtAppartement = '' ) { log('info', 'Fetching user data') const sgeHeaders = { @@ -33,7 +34,14 @@ async function findUserPdl( const { response } = await soapRequest({ url: url, headers: sgeHeaders, - xml: rechercherPoint(appLogin, name, postalCode, inseeCode, address), + xml: rechercherPoint( + appLogin, + name, + postalCode, + inseeCode, + address, + escalierEtEtageEtAppartement + ), }).catch(err => { log('error', 'rechercherPointResponse') log('error', err) @@ -56,7 +64,6 @@ async function findUserPdl( `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}` ) } - throw errors.LOGIN_FAILED } } diff --git a/src/core/index.js b/src/core/index.js index e9bf3ed..70e2d7e 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -4,6 +4,7 @@ const { terminateContract } = require('./contractTermination') const { verifyContract } = require('./contractVerification') const { findUserPdl } = require('./findUserPdl') const { verifyUserIdentity } = require('./verifyUserIdentity') +const { findUserAddress } = require('./findUserAddress') module.exports = { activateContract, @@ -12,4 +13,5 @@ module.exports = { verifyContract, findUserPdl, verifyUserIdentity, + findUserAddress, } diff --git a/src/core/types/types.js b/src/core/types/types.js index e69c308..e313730 100644 --- a/src/core/types/types.js +++ b/src/core/types/types.js @@ -87,3 +87,19 @@ * @property {number} consentId * @property {string} inseeCode */ + +/** + * Address definition + * @typedef {object} Address + * @property {string} escalierEtEtageEtAppartement + * @property {string} numeroEtNomVoie + * @property {string} codePostal + * @property {Commune} commune + */ + +/** + * Commune definition + * @typedef {object} Commune + * @property {{code: string}} $ + * @property {string} libelle + */ diff --git a/src/core/verifyUserIdentity.js b/src/core/verifyUserIdentity.js index 086303e..e093c4c 100644 --- a/src/core/verifyUserIdentity.js +++ b/src/core/verifyUserIdentity.js @@ -2,6 +2,11 @@ const { log, errors } = require('cozy-konnector-libs') const { findUserPdl } = require('./findUserPdl') const { getInseeCode } = require('../requests/insee') +const { findUserAddress } = require('./findUserAddress') +const { + removeMultipleSpaces, + removeAddressnumber, +} = require('../helpers/parsing') /** * Verify user identity @@ -26,7 +31,8 @@ async function verifyUserIdentity( inseeCode = await getInseeCode(fields.postalCode, fields.city) } - const pdl = await findUserPdl( + // First try with user adresse + let pdl = await findUserPdl( `${baseUrl}/enedis_SDE_recherche-point/1.0`, apiAuthKey, loginUtilisateur, @@ -36,8 +42,50 @@ async function verifyUserIdentity( inseeCode ) + if (!pdl) { + log('warn', 'Second change for sge onboarding') + // Backup verification + const userAddress = await findUserAddress( + baseUrl, + apiAuthKey, + loginUtilisateur, + fields.pointId + ) + + const escalierEtEtageEtAppartement = userAddress.escalierEtEtageEtAppartement + ? removeMultipleSpaces(userAddress.escalierEtEtageEtAppartement) + : '' + + pdl = await findUserPdl( + `${baseUrl}/enedis_SDE_recherche-point/1.0`, + apiAuthKey, + loginUtilisateur, + fields.lastname, + removeMultipleSpaces(userAddress.numeroEtNomVoie), + userAddress.codePostal, + userAddress.commune.$.code, + escalierEtEtageEtAppartement + ) + + // Third try, remove address number because it's buggy on SGE side + if (!pdl) { + log('warn', 'Lastchance onboarding for sge') + pdl = await findUserPdl( + `${baseUrl}/enedis_SDE_recherche-point/1.0`, + apiAuthKey, + loginUtilisateur, + fields.lastname, + removeMultipleSpaces(removeAddressnumber(userAddress.numeroEtNomVoie)), + userAddress.codePostal, + userAddress.commune.$.code, + escalierEtEtageEtAppartement + ) + } + } + if (fields.pointId != pdl) { log('error', 'PointId does not match') + if (isAlternateStart) { throw errors.TERMS_VERSION_MISMATCH } else { diff --git a/src/helpers/parsing.js b/src/helpers/parsing.js index 1d10a74..ea5de16 100644 --- a/src/helpers/parsing.js +++ b/src/helpers/parsing.js @@ -29,6 +29,18 @@ function parseContractStartDate(result) { 'dateDerniereModificationFormuleTarifaireAcheminement' ] } +/** + * 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 contract start date @@ -127,6 +139,24 @@ function parseValue(value, name) { return value } +/** + * Remove SGE useless multiple white spaces + * @param {string} str + * @returns {string} + */ +function removeMultipleSpaces(str) { + return str.replace(/ +/g, ' ') +} + +/** + * Remove SGE useless multiple white spaces + * @param {string} str + * @returns {string} + */ +function removeAddressnumber(str) { + return str.replace(/[0-9]|b |B |T |t /g, '') +} + module.exports = { parseSgeXmlData, formateDataForDoctype, @@ -136,5 +166,8 @@ module.exports = { parseContracts, parseContractStartDate, parseServiceId, + parseUserAddress, checkContractExists, + removeMultipleSpaces, + removeAddressnumber, } diff --git a/src/requests/sge.js b/src/requests/sge.js index 518c624..402aa7a 100644 --- a/src/requests/sge.js +++ b/src/requests/sge.js @@ -102,7 +102,11 @@ function consultationMesuresDetailleesMaxPower( * @param {string} appLogin * @returns {string} */ -function consulterDonneesTechniquesContractuelles(pointId, appLogin) { +function consulterDonneesTechniquesContractuelles( + pointId, + appLogin, + consent = true +) { log('info', `Query consulterDonneesTechniquesContractuelles`) return `<?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" @@ -113,7 +117,7 @@ function consulterDonneesTechniquesContractuelles(pointId, appLogin) { <v2:consulterDonneesTechniquesContractuelles> <pointId>${pointId}</pointId> <loginUtilisateur>${appLogin}</loginUtilisateur> - <autorisationClient>true</autorisationClient> + <autorisationClient>${consent}</autorisationClient> </v2:consulterDonneesTechniquesContractuelles> </soapenv:Body> </soapenv:Envelope> @@ -125,14 +129,45 @@ function consulterDonneesTechniquesContractuelles(pointId, appLogin) { * @param {string} name * @param {string} postalCode * @param {string} inseeCode - * @param {string} [address] + * @param {string} address + * @param {string} [escalierEtEtageEtAppartement] * @returns {string} PDL */ -function rechercherPoint(appLogin, name, postalCode, inseeCode, address) { +function rechercherPoint( + appLogin, + name, + postalCode, + inseeCode, + address, + escalierEtEtageEtAppartement +) { log( 'info', `Query rechercherPoint - postal code / insee code: ${postalCode} / ${inseeCode}` ) + if (escalierEtEtageEtAppartement) { + return `<?xml version='1.0' encoding='utf-8'?> + <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:v2="http://www.enedis.fr/sge/b2b/services/rechercherpoint/v2.0" + xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0"> + <soapenv:Header/> + <soapenv:Body> + <v2:rechercherPoint> + <criteres> + <adresseInstallation> + <escalierEtEtageEtAppartement>${escalierEtEtageEtAppartement}</escalierEtEtageEtAppartement> + <numeroEtNomVoie>${address}</numeroEtNomVoie> + <codePostal>${postalCode}</codePostal> + <codeInseeCommune>${inseeCode}</codeInseeCommune> + </adresseInstallation> + <nomClientFinalOuDenominationSociale>${name}</nomClientFinalOuDenominationSociale> + <rechercheHorsPerimetre>true</rechercheHorsPerimetre> + </criteres> + <loginUtilisateur>${appLogin}</loginUtilisateur> + </v2:rechercherPoint> + </soapenv:Body> + </soapenv:Envelope>` + } return `<?xml version='1.0' encoding='utf-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://www.enedis.fr/sge/b2b/services/rechercherpoint/v2.0" -- GitLab