/** * Utils for looking up postcodes from addresses */ 'use strict'; const debug = require('debug')('utils:postcodes'); const Q = require('q'); const config = require(global.configFile); const idealPostcodes = require('ideal-postcodes')(config.idealPostcodesKey); const UkClearAddressing = require('uk-clear-addressing'); const ERRORS = { UNSPECIFIED: 'Unspecified error' }; module.exports = { ERRORS, postcodeLookup }; /** * Runs a postcode lookup and returns a list of addresses that could match that * postcode. * * @param {string} postcode - the postcode to lookup addresses for * @returns {Promise} - promise for array of addressses */ function postcodeLookup(postcode) { debug('Postcode Lookup: ', postcode); return Q.ninvoke( idealPostcodes, 'lookupPostcode', postcode ).then((addresses) => { const formatted = []; for (let i = 0; i < addresses.length; ++i) { formatted.push(pafToBridgeAddress(addresses[i])); } debug('Formatted:', formatted); return formatted; }).catch(() => { // // The API doesn't really make it possible to differentatiate errors at // this time. // const newError = ERRORS.UNSPECIFIED; return Q.reject(newError); }); } /** * Converst a PAF (Royal Mail Postcode Address File) format address to a * Bridge style one. * * @param {Object} pafAddr - the address is PAF format * @returns {Object} - the address in Bridge format */ function pafToBridgeAddress(pafAddr) { // // Use the uk-clear-addressing module to do most of the work for us // const clearAddr = new UkClearAddressing(pafAddr).formattedAddress(); // Disable the variable case error because uk-clear-addressing uses snake case // jshint -W106 const bridgeAddress = { Town: clearAddr.post_town, PostCode: clearAddr.postcode, Country: 'United Kingdom' }; if (clearAddr.line_3) { // // The address has 3 lines, so put the first one in BuildingNameFlat // bridgeAddress.BuildingNameFlat = clearAddr.line_1; bridgeAddress.Address1 = clearAddr.line_2; bridgeAddress.Address2 = clearAddr.line_3; } else if (clearAddr.line_1 === pafAddr.sub_building_name) { // // We differentiate between "BuildingNameFlat" and Address1, whereas // UkClearAddressing doesn't. So if line_1 is just the sub building name, // then put that in flat, and move line 2 up. // bridgeAddress.BuildingNameFlat = clearAddr.line_1; bridgeAddress.Address1 = clearAddr.line_2; } else { // // This address has at most 2 lines, so just use the main fields. // bridgeAddress.Address1 = clearAddr.line_1; bridgeAddress.Address2 = clearAddr.line_2; } // // Convert the fields accross to our names for them. // return bridgeAddress; }