From 1ce4015ffaec9cc06c2a2c62e24e40189c3d19e7 Mon Sep 17 00:00:00 2001 From: egg Date: Tue, 22 Jun 2021 16:21:06 +0900 Subject: [PATCH] * add Canada Post --- README.md | 2 + bin/index.js | 2 +- lib/courier/canadapost.js | 73 ++++++++++++++++++++++++++++++ lib/index.js | 4 ++ package.json | 5 +- test/canadapost.js | 31 +++++++++++++ test/fixtures/canadapost-DELIVERED | 2 + 7 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 lib/courier/canadapost.js create mode 100644 test/canadapost.js create mode 100644 test/fixtures/canadapost-DELIVERED diff --git a/README.md b/README.md index 873ae7c..e16e0cb 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ eParcel | @egg- | https://eparcel.kr/ LBC | @egg- | https://www.lbcexpress.com/ J&T (PH) | @egg- | https://www.jtexpress.ph/ DHL | @carstenschwede | https://www.dhl.com/ +Canada Post | @egg- | https://www.canadapost-postescanada.ca/ ## Installation @@ -127,6 +128,7 @@ EPARCEL | eparcel | eParcel LBC | lbc | LBC JNT | jnt | J&T DHL | dhl | DHL +CANADAPOST | canadapost | Canada Post ### STATUS diff --git a/bin/index.js b/bin/index.js index e907b00..d6c2405 100644 --- a/bin/index.js +++ b/bin/index.js @@ -5,7 +5,7 @@ var tracker = require('../') program .arguments('') - .option('-c, --courier ', 'Courier Namespace', /^(KOREAPOST|ECARGO|FEDEX|PANTOS|RINCOS|AUSPOST|ROYALMAIL|USPS|CJKOREAEXPRESS|POSLAJU|YELLOEXPRESS|EFS|AIRBRIDGE|UPS|TNT|CESCO|XPOST|KERRYTHAI|SICEPAT|XIOEXPRESS|EPARCEL|LBC|JNT|DHL)$/i) + .option('-c, --courier ', 'Courier Namespace', /^(KOREAPOST|ECARGO|FEDEX|PANTOS|RINCOS|AUSPOST|ROYALMAIL|USPS|CJKOREAEXPRESS|POSLAJU|YELLOEXPRESS|EFS|AIRBRIDGE|UPS|TNT|CESCO|XPOST|KERRYTHAI|SICEPAT|XIOEXPRESS|EPARCEL|LBC|JNT|DHL|CANADAPOST)$/i) .option('-k, --apikey ', 'API KEY') .action(function (tracecode) { if (!tracker.COURIER[program.courier]) { diff --git a/lib/courier/canadapost.js b/lib/courier/canadapost.js new file mode 100644 index 0000000..406ad6f --- /dev/null +++ b/lib/courier/canadapost.js @@ -0,0 +1,73 @@ +'use strict' + +var request = require('request') +var moment = require('moment') + +var tracker = require('../') + +var trackingInfo = function (number) { + return { + method: 'GET', + url: 'https://www.canadapost-postescanada.ca/track-reperage/rs/track/json/package/' + number + '/detail' + } +} + +var parser = { + trace: function (data) { + var courier = { + code: tracker.COURIER.CANADAPOST.CODE, + name: tracker.COURIER.CANADAPOST.NAME + } + var result = { + courier: courier, + number: data.pin, + status: tracker.STATUS.PENDING + } + + var checkpoints = [] + for (var i = 0; i < data.events.length; i++) { + var item = data.events[i] + var checkpoint = { + courier: courier, + location: item.locationAddr.countryNmEn ? item.locationAddr.countryNmEn + ' ' + item.locationAddr.city : '', + message: item.descEn, + status: tracker.STATUS.IN_TRANSIT, + time: moment(item.datetime.date + ' ' + item.datetime.time + 'T' + item.datetime.zoneOffset, 'YYYY-MM-DD HH:mm:ssZ').utc().format('YYYY-MM-DDTHH:mmZ') + } + + if (item.type === 'Delivered') { + checkpoint.status = tracker.STATUS.DELIVERED + } else if (item.type === 'Induction') { + checkpoint.status = tracker.STATUS.INFO_RECEIVED + } + checkpoints.push(checkpoint) + } + + result.checkpoints = checkpoints + result.status = tracker.normalizeStatus(result.checkpoints) + + return result + } +} + +module.exports = function () { + return { + trackingInfo: trackingInfo, + trace: function (number, cb) { + var tracking = trackingInfo(number) + + request(tracking, function (err, res, body) { + if (err) { + return cb(err) + } + + try { + var result = parser.trace(JSON.parse(body)) + cb(result ? null : tracker.error(tracker.ERROR.INVALID_NUMBER), result) + } catch (e) { + cb(tracker.error(e.message)) + } + }) + } + } +} diff --git a/lib/index.js b/lib/index.js index f53d122..ed60ab8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -105,6 +105,10 @@ var COURIER = { DHL: { CODE: 'dhl', NAME: 'DHL' + }, + CANADAPOST: { + CODE: 'canadapost', + NAME: 'Canada Post' } } diff --git a/package.json b/package.json index 03e087c..21f5fa0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "delivery-tracker", - "version": "2.6.1", + "version": "2.7.0", "author": { "name": "egg", "email": "i@egg.pe.kr" @@ -52,7 +52,8 @@ "lbc", "j&t", "jnt", - "dhl" + "dhl", + "canada post" ], "license": "MIT", "bugs": { diff --git a/test/canadapost.js b/test/canadapost.js new file mode 100644 index 0000000..a099d67 --- /dev/null +++ b/test/canadapost.js @@ -0,0 +1,31 @@ +/* globals before it describe */ + +'use strict' + +var assert = require('assert') + +var prepare = require('./fixtures/prepare') +var tracker = require('../') + +var courier = tracker.courier(tracker.COURIER.CANADAPOST.CODE) + +describe(tracker.COURIER.CANADAPOST.NAME, function () { + var deliveredNumber = 'DELIVERED' + + before(function () { + // @TODO add nock + prepare(courier, deliveredNumber) + }) + + it('delivered number', function (done) { + courier.trace(deliveredNumber, function (err, result) { + assert.equal(err, null) + + assert.equal(deliveredNumber, result.number) + assert.equal(tracker.COURIER.CANADAPOST.CODE, result.courier.code) + assert.equal(tracker.STATUS.DELIVERED, result.status) + + done() + }) + }) +}) diff --git a/test/fixtures/canadapost-DELIVERED b/test/fixtures/canadapost-DELIVERED new file mode 100644 index 0000000..5cb8047 --- /dev/null +++ b/test/fixtures/canadapost-DELIVERED @@ -0,0 +1,2 @@ + +{"pin":"DELIVERED","productNmEn":"Expedited Parcels","productNmFr":"Colis accélérés","productNbr":"000000000000000967","refNbr1":"LETIAN6608054","refNbr2":"LETIAN6608054","finalEvent":true,"delivered":true,"status":"Delivered","shippedDateTime":{"date":"2021-06-05","time":"03:37:45","zoneOffset":"-04:00"},"expectedDlvryDateTime":{"revisedDate":"2021-06-21","revisionReasonEn":"Item was received by Canada Post after cut-off time.","revisionReasonFr":"Postes Canada a reçu l'article après l'heure limite.","dlvryDate":"2021-06-23"},"attemptedDlvryDate":"2021-06-21","actualDlvryDate":"2021-06-21","shipFromAddr":{"addrLn1":"","addrLn2":"","countryCd":"","city":"","regionCd":"","postCd":"c5bbb7dae495231783e1517cdbda4aa9"},"shipToAddr":{"addrLn1":"","addrLn2":"","countryCd":"","city":"","regionCd":"","postCd":"c30d284f296849d54d30e5a56690e685"},"events":[{"cd":"1441","webCd":"CODE-820","datetime":{"date":"2021-06-21","time":"11:38:02","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"WATERFORD","regionCd":"ON","postCd":"c30d284f296849d54d30e5a56690e685"},"descEn":"Delivered to your community mailbox, parcel locker or apt./condo mailbox","descFr":"Livré à votre boîte postale, armoire à colis ou boîte aux lettres de l'app/condo","type":"Delivered"},{"cd":"0174","webCd":"CODE-514","datetime":{"date":"2021-06-21","time":"09:42:22","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"WATERFORD","regionCd":"ON","postCd":"c30d284f296849d54d30e5a56690e685"},"descEn":"Item out for delivery","descFr":"Article sorti pour livraison","type":"Out"},{"cd":"0170","webCd":"CODE-446","datetime":{"date":"2021-06-21","time":"08:16:37","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"WATERFORD","regionCd":"ON","postCd":"c30d284f296849d54d30e5a56690e685"},"descEn":"Item processed","descFr":"Article traité","type":"Info"},{"cd":"0175","webCd":"CODE-850","datetime":{"date":"2021-06-18","time":"15:10:59","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"STONEY CREEK","regionCd":"ON","postCd":"c35553737e24e6aa58cbfa712315a5da"},"descEn":"Item in transit","descFr":"Article en transit","type":"Info"},{"cd":"0104","webCd":"CODE-446","datetime":{"date":"2021-06-18","time":"12:14:03","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"STONEY CREEK","regionCd":"ON","postCd":"c35553737e24e6aa58cbfa712315a5da"},"descEn":"Item processed","descFr":"Article traité","type":"Info"},{"cd":"0410","webCd":"CODE-868","datetime":{"date":"2021-06-18","time":"02:06:22","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"MISSISSAUGA","regionCd":"ON","postCd":"4f1e8ef1c47ed0049dd012f06feb0efa"},"descEn":"Item departed","descFr":"L'article est parti","type":"VehicleInfo"},{"cd":"0100","webCd":"CODE-446","datetime":{"date":"2021-06-18","time":"01:22:37","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"MISSISSAUGA","regionCd":"ON","postCd":"4f1e8ef1c47ed0049dd012f06feb0efa"},"descEn":"Item processed","descFr":"Article traité","type":"Info"},{"cd":"0910","webCd":"CODE-852","datetime":{"date":"2021-06-14","time":"11:03:00","zoneOffset":"-03:00"},"locationAddr":{"countryCd":"CA","countryNmEn":"Canada","countryNmFr":"Canada","city":"VANCOUVER","regionCd":"BC","postCd":"880c19ecdefa906129372b317ea426f1"},"descEn":"Item was released by Customs and is now with Canada Post for processing","descFr":"Dédouanement complété. Article fut expédié au centre du traitement de courrier.","type":"FromCust"},{"cd":"3000","webCd":"CODE-020A","datetime":{"date":"2021-06-05","time":"03:37:45","zoneOffset":"-04:00"},"locationAddr":{"countryCd":"","city":"","regionCd":"","postCd":""},"descEn":"Electronic information submitted by shipper","descFr":"Les renseignements électroniques ont été soumis par l'expéditeur","type":"Induction"}],"custNm":"LETIAN PARCEL","addtnlOrigInfo":"MISSISSAUGA, ON","addtnlDestInfo":"WATERFORD, ON","suppressSignature":false,"lagTime":false,"returnPinIndicator":false,"refundAllowed":false,"dtcBarcode":false,"canadianDest":true,"dlvryInstruction":"","correctedPostalCode":"","sigReqByAmtDue":false,"shipperPostalCode":"L3R6B6","recipientNm":"*****","deliveryCertificateOption":"NO_AUTHORIZATION"} \ No newline at end of file