const axios = require('axios'); const {DOMParser} = require('xmldom'); const fs = require('fs'); const ejs = require('ejs'); const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethod('createShipment', { description: 'Create an expedition and return a base64Binary label from de MRW WebService', accessType: 'WRITE', accepts: [{ arg: 'expeditionFk', type: 'number', required: true }], returns: { type: ['object'], root: true }, http: { path: `/createShipment`, verb: 'POST' } }); Self.createShipment = async(expeditionFk, options) => { const myOptions = {}; let tx; if (typeof options == 'object') Object.assign(myOptions, options); if (!myOptions.transaction) { tx = await Self.beginTransaction({}); myOptions.transaction = tx; } const models = Self.app.models; const mrw = await models.MrwConfig.findOne(null, myOptions); if (!mrw) throw new UserError(`Some mrwConfig parameters are not set`); const query = `SELECT CASE co.code WHEN 'ES' THEN a.postalCode WHEN 'PT' THEN LEFT(a.postalCode, 4) WHEN 'AD' THEN REPLACE(a.postalCode, 'AD', '00') END postalCode, a.city, a.street, co.code countryCode, c.fi, c.name clientName, c.phone, DATE_FORMAT(t.shipped, '%d/%m/%Y') created, t.shipped, e.id expeditionId, LPAD(IF(mw.params IS NULL, ms.serviceType, mw.serviceType), 4 ,'0') serviceType, IF(mw.weekdays, 'S', 'N') weekDays FROM expedition e JOIN ticket t ON e.ticketFk = t.id JOIN agencyMode am ON am.id = t.agencyModeFk JOIN mrwService ms ON ms.agencyModeCodeFk = am.code LEFT JOIN mrwServiceWeekday mw ON mw.weekdays = DATE_FORMAT(t.shipped, '%a') JOIN client c ON t.clientFk = c.id JOIN address a ON t.addressFk = a.id JOIN province p ON a.provinceFk = p.id JOIN country co ON co.id = p.countryFk WHERE e.id = ? LIMIT 1`; const [expeditionData] = await Self.rawSql(query, [expeditionFk], myOptions); if (!expeditionData) throw new UserError(`This expedition is not a MRW shipment`); const today = Date.vnNew(); today.setHours(0, 0, 0, 0); if (expeditionData?.shipped.setHours(0, 0, 0, 0) < today) throw new UserError(`This ticket has a shipped date earlier than today`); const shipmentResponse = await sendXmlDoc('createShipment', {mrw, expeditionData}, 'application/soap+xml'); const shipmentId = getTextByTag(shipmentResponse, 'NumeroEnvio'); if (!shipmentId) throw new UserError(getTextByTag(shipmentResponse, 'Mensaje')); const getLabelResponse = await sendXmlDoc('getLabel', {mrw, shipmentId}, 'text/xml'); const file = getTextByTag(getLabelResponse, 'EtiquetaFile'); try { await models.Expedition.updateAll({id: expeditionFk}, {externalId: shipmentId}, myOptions); if (tx) await tx.commit(); } catch (error) { if (tx) await tx.rollback(); throw error; } return file; }; function getTextByTag(xmlDoc, tag) { return xmlDoc?.getElementsByTagName(tag)[0]?.textContent; } async function sendXmlDoc(xmlDock, params, contentType) { const parser = new DOMParser(); const xmlTemplate = fs.readFileSync(__dirname + `/${xmlDock}.ejs`, 'utf-8'); const renderedTemplate = ejs.render(xmlTemplate, params); const data = await axios.post(params.mrw.url, renderedTemplate, { headers: { 'Content-Type': `${contentType}; charset=utf-8` } }); return parser.parseFromString(data.data, 'text/xml'); } };