diff --git a/download-shipping-labels.js b/download-shipping-labels.js index 5d6b894..4baf027 100644 --- a/download-shipping-labels.js +++ b/download-shipping-labels.js @@ -7,10 +7,13 @@ const path = require("path"); const dotenv = require("dotenv").config({ path: __dirname + "/.env" }); const utils = require("./utils"); +const emailUtils = require("./email-utils"); (async function () { console.log( - `===========< STARTED --- DOWNLOAD SHIPPING LABELS ${utils.getPakistanStandardTime(luxon.DateTime.now())} >=========` + `===========< STARTED --- DOWNLOAD SHIPPING LABELS ${utils.getPakistanStandardTime( + luxon.DateTime.now() + )} >=========` ); const syncDate = luxon.DateTime.now().toFormat("yyyy-MM-dd"); @@ -21,16 +24,15 @@ const utils = require("./utils"); const config = JSON.parse(fs.readFileSync(__dirname + "/config.json")); const environment = process.env["ENVIRONMENT"]; const cryptoConfig = utils.getCryptoConfig(); - const state = JSON.parse(fs.readFileSync(__dirname + "/state.json")); const email = utils.decryptString( - process.env["temu-personal-email"], + process.env["temu-umair-email"], cryptoConfig.algo, cryptoConfig.key, cryptoConfig.iv ); const password = utils.decryptString( - process.env["temu-personal-password"], + process.env["temu-umair-password"], cryptoConfig.algo, cryptoConfig.key, cryptoConfig.iv @@ -121,55 +123,6 @@ const utils = require("./utils"); let currentPage = 1; let maxPage = 5; - await new Promise((resolve) => setTimeout(resolve, 2_000)); - // set the pagination to 100 / page - const pageinationSeletor = - "#orders-tab-list > div.y0DVv7GO > div > div._38NAUUfN > div._15QWqbZs > ul > li.PGT_sizeChanger_123 > div > div > div > div > div"; - await page.waitForSelector(pageinationSeletor); - await page.click(pageinationSeletor); - console.log("Clicking on pagination Select"); - await new Promise((resolve) => setTimeout(resolve, 3_000)); - - // select 100 /page option - const pagesPerPageSelector = - "body > div.PT_outerWrapper_123.PP_outerWrapper_123.ST_dropdown_123.ST_mediumDropdown_123.PT_dropdown_123.PT_portalTopLeft_123.PT_inCustom_123.PP_dropdown_123 > div > div > div > div > ul > li:nth-child(5)"; - await page.waitForSelector(pagesPerPageSelector); - await page.click(pagesPerPageSelector); - await new Promise((resolve) => setTimeout(resolve, 1_000)); - - /** - * Capture response - */ - const checkShippingLabelResponse = async (page, timer) => { - return new Promise((resolve, reject) => { - // Timeout mechanism to resolve with an empty list after 5 seconds - const timeout = setTimeout(() => { - page.off("response", handleResponse); // Remove listener on timeout - resolve([]); // Resolve with an empty list - }, timer); - - const handleResponse = async (res) => { - try { - const req = res.request(); - if (req.url().includes("/batch_print_shipping_label")) { - const resJson = await res.json(); - // Remove listener and clear timeout once response is captured - clearTimeout(timeout); - page.off("response", handleResponse); - resolve(resJson || []); - } - } catch (ex) { - // Remove listener and clear timeout on error - clearTimeout(timeout); - page.off("response", handleResponse); - reject(ex); - } - }; - - page.on("response", handleResponse); - }); - }; - const downloadFolderPath = path.resolve( config[environment].temu_order_shipping_labels_path, `unprocessed/` @@ -180,24 +133,58 @@ const utils = require("./utils"); `processed/` ); - /* - * update state - */ - const updateState = async (pageNumber, date) => { - try { - // update state - const stateJson = { - last_updated: date, - last_page: pageNumber, - }; + try { + await new Promise((resolve) => setTimeout(resolve, 2_000)); + // set the pagination to 100 / page + const pageinationSeletor = + "#orders-tab-list > div.y0DVv7GO > div > div._38NAUUfN > div._15QWqbZs > ul > li.PGT_sizeChanger_123 > div > div > div > div > div"; + await page.waitForSelector(pageinationSeletor); + await page.click(pageinationSeletor); + console.log("Clicking on pagination Select"); + await new Promise((resolve) => setTimeout(resolve, 3_000)); - // File path to save the JSON - const filePath = path.join(__dirname, "state.json"); - fs.writeFileSync(filePath, JSON.stringify(stateJson, null, 2)); - } catch (e) { - console.log(e); - } - }; + // select 100 /page option + const pagesPerPageSelector = + "body > div.PT_outerWrapper_123.PP_outerWrapper_123.ST_dropdown_123.ST_mediumDropdown_123.PT_dropdown_123.PT_portalTopLeft_123.PT_inCustom_123.PP_dropdown_123 > div > div > div > div > ul > li:nth-child(5)"; + await page.waitForSelector(pagesPerPageSelector); + await page.click(pagesPerPageSelector); + await new Promise((resolve) => setTimeout(resolve, 1_000)); + + /** + * Capture response + */ + const checkShippingLabelResponse = async (page, timer) => { + return new Promise((resolve, reject) => { + // Timeout mechanism to resolve with an empty list after 5 seconds + const timeout = setTimeout(() => { + page.off("response", handleResponse); // Remove listener on timeout + resolve([]); // Resolve with an empty list + }, timer); + + const handleResponse = async (res) => { + try { + const req = res.request(); + if (req.url().includes("/batch_print_shipping_label")) { + const resJson = await res.json(); + // Remove listener and clear timeout once response is captured + clearTimeout(timeout); + page.off("response", handleResponse); + resolve(resJson || []); + } + } catch (ex) { + // Remove listener and clear timeout on error + clearTimeout(timeout); + page.off("response", handleResponse); + reject(ex); + } + }; + + page.on("response", handleResponse); + }); + }; + } catch (e) { + emailUtils.notify(`Download Order Shipping Labels`, e.message); + } /* * download labels @@ -343,8 +330,6 @@ const utils = require("./utils"); console.log(`Total Pages count : ${total_pages}`); while (true) { - // update state - // await updateState(currentPage, luxon.DateTime.now().toISO()); console.log(`Crawling for page ${currentPage}`); await new Promise((resolve) => setTimeout(resolve, 2_000)); @@ -395,14 +380,14 @@ const utils = require("./utils"); await new Promise((r) => setTimeout(r, 5000)); } } catch (e) { + emailUtils.notify(`Download Shipping Labels`, e.message); console.log(e); } - // update state - // await updateState(1, luxon.DateTime.now().toISO()); - console.log( - `==========< ENDED --- DOWNLOAD SHIPPING LABELS ${utils.getPakistanStandardTimeluxon.DateTime.now()} >==========` + `==========< ENDED --- DOWNLOAD SHIPPING LABELS ${utils.getPakistanStandardTime( + luxon.DateTime.now() + )} >==========` ); await page.close(); await browser.close(); diff --git a/email-utils.js b/email-utils.js new file mode 100644 index 0000000..1024685 --- /dev/null +++ b/email-utils.js @@ -0,0 +1,42 @@ +const AWS = require("aws-sdk"); +const nodemailer = require("nodemailer"); +const utils = require("./utils"); + +const SES_CONFIG = { + accessKeyId: "AKIAWCDCR7WSPJMY7OUU", + secretAccessKey: "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", + region: "us-east-1", +}; + +// SES object +const AWS_SES = new AWS.SES(SES_CONFIG); +// Create an Amazon SES transporter +const transporter = nodemailer.createTransport({ + SES: AWS_SES, +}); + +// send email using transporter send to multiple tos +const notify = (subject, body) => { + // params + let recipients = ["saif.haq@utopia.pk", "huzaifa.jiwani@utopia.pk"]; + let emailSubject = `Utopia Deals Temu FBU ${subject} Job`; + let emailBody = `

${body}

`; + + const mailOptions = { + from: `uRobot@utopiadeals.com`, + to: recipients, + subject: emailSubject, + html: emailBody, + }; + + transporter.sendMail(mailOptions, (error, info) => { + if (error) { + console.error("Error sending email:", error); + } else { + console.info("Email sent successfully:", info.response); + } + }); +}; + +//export send email function +exports.notify = notify; diff --git a/package-lock.json b/package-lock.json index eccf119..429f8ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,14 @@ "dependencies": { "@aws-sdk/client-s3": "^3.734.0", "@aws-sdk/lib-storage": "^3.734.0", + "aws-sdk": "^2.1692.0", "axios": "^0.27.2", "base32-encode": "^2.0.0", "dotenv": "^16.0.3", "express": "^4.18.1", "luxon": "^3.3.0", "node-fetch": "^3.3.2", + "nodemailer": "^6.10.0", "otplib": "^12.0.1", "puppeteer": "^22.8.2", "thirty-two": "^1.0.2", @@ -1726,6 +1728,72 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1692.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", + "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", + "hasInstallScript": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/aws-sdk/node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/aws-sdk/node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/axios": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", @@ -1886,6 +1954,23 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", @@ -2078,6 +2163,22 @@ "ms": "2.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/degenerator": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", @@ -2468,6 +2569,20 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/form-data": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", @@ -2555,6 +2670,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -2622,6 +2749,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -2633,6 +2771,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -2795,11 +2947,37 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2808,6 +2986,67 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2978,6 +3217,14 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/nodemailer": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", + "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", @@ -3120,6 +3367,14 @@ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -3193,6 +3448,11 @@ "once": "^1.3.1" } }, + "node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, "node_modules/puppeteer": { "version": "22.15.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.15.0.tgz", @@ -3261,6 +3521,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/queue-tick": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", @@ -3336,11 +3605,32 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -3402,6 +3692,22 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -3723,11 +4029,32 @@ "node": ">= 0.8" } }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, "node_modules/urlpattern-polyfill": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==" }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3769,6 +4096,25 @@ "node": ">= 8" } }, + "node_modules/which-typed-array": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wmf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", @@ -3846,6 +4192,26 @@ "node": ">=0.8" } }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 638f299..ef389da 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,14 @@ "dependencies": { "@aws-sdk/client-s3": "^3.734.0", "@aws-sdk/lib-storage": "^3.734.0", + "aws-sdk": "^2.1692.0", "axios": "^0.27.2", "base32-encode": "^2.0.0", "dotenv": "^16.0.3", "express": "^4.18.1", "luxon": "^3.3.0", "node-fetch": "^3.3.2", + "nodemailer": "^6.10.0", "otplib": "^12.0.1", "puppeteer": "^22.8.2", "thirty-two": "^1.0.2", diff --git a/sync-orders.js b/sync-orders.js index 0d550b9..1722304 100644 --- a/sync-orders.js +++ b/sync-orders.js @@ -8,9 +8,14 @@ const xlsx = require("xlsx"); const dotenv = require("dotenv").config({ path: __dirname + "/.env" }); const utils = require("./utils"); +const emailUtils = require("./email-utils"); (async function () { - console.log(`===========< STARTED ${utils.getPakistanStandardTime(luxon.DateTime.now())} >=========`); + console.log( + `===========< STARTED ${utils.getPakistanStandardTime( + luxon.DateTime.now() + )} >=========` + ); const syncDate = luxon.DateTime.now().toFormat("yyyy-MM-dd"); @@ -120,40 +125,24 @@ const utils = require("./utils"); /* * request order report */ - const orderRequestSelector = "div._3yOxLjm0._2pgGmJ7w.IoqjAtdZ.vbGE0cGC"; - const element = await page.$(orderRequestSelector); - if (element) { - // wait for 5 sec - await new Promise((resolve) => setTimeout(resolve, 5 * 1000)); - await element.click(); - console.log("Clicked on the Request Report btn"); - // take screenshot - let screenshotPath = path.join( - screenshotDirectory, - `${luxon.DateTime.now().toMillis()}.png` - ); - await page.screenshot({ path: screenshotPath, fullPage: true }); - // wait 10 secs - await new Promise((resolve) => setTimeout(resolve, 10 * 1000)); - - // take screenshot - screenshotPath = path.join( - screenshotDirectory, - `${luxon.DateTime.now().toMillis()}.png` - ); - await page.screenshot({ path: screenshotPath, fullPage: true }); - // wait 10 secs - await new Promise((resolve) => setTimeout(resolve, 10 * 1000)); - - const confirmBtnSelector = "div._3yOxLjm0._2pgGmJ7w._1eT_m6dA"; - const confirmBtnElement = await page.$(confirmBtnSelector); - if (confirmBtnElement) { - await new Promise((resolve) => setTimeout(resolve, 15 * 1000)); - await confirmBtnElement.click(); - console.log("Clicked on the Confirm Button"); - // wait for 3 seconds then reload page + try { + const orderRequestSelector = "div._3yOxLjm0._2pgGmJ7w.IoqjAtdZ.vbGE0cGC"; + const element = await page.$(orderRequestSelector); + if (element) { + // wait for 5 sec await new Promise((resolve) => setTimeout(resolve, 5 * 1000)); + await element.click(); + console.log("Clicked on the Request Report btn"); + // take screenshot + let screenshotPath = path.join( + screenshotDirectory, + `${luxon.DateTime.now().toMillis()}.png` + ); + await page.screenshot({ path: screenshotPath, fullPage: true }); + + // wait 10 secs + await new Promise((resolve) => setTimeout(resolve, 10 * 1000)); // take screenshot screenshotPath = path.join( @@ -161,69 +150,90 @@ const utils = require("./utils"); `${luxon.DateTime.now().toMillis()}.png` ); await page.screenshot({ path: screenshotPath, fullPage: true }); + // wait 10 secs + await new Promise((resolve) => setTimeout(resolve, 10 * 1000)); + + const confirmBtnSelector = "div._3yOxLjm0._2pgGmJ7w._1eT_m6dA"; + const confirmBtnElement = await page.$(confirmBtnSelector); + if (confirmBtnElement) { + await new Promise((resolve) => setTimeout(resolve, 15 * 1000)); + await confirmBtnElement.click(); + console.log("Clicked on the Confirm Button"); + // wait for 3 seconds then reload page + await new Promise((resolve) => setTimeout(resolve, 5 * 1000)); + + // take screenshot + screenshotPath = path.join( + screenshotDirectory, + `${luxon.DateTime.now().toMillis()}.png` + ); + await page.screenshot({ path: screenshotPath, fullPage: true }); + } + } else { + console.log(" Request Btn doest exists"); } - } else { - console.log(" Request Btn doest exists"); - } - // wait for 5 mins for request to be processed - await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)); - await page.reload(); - console.log("Page reloaded"); - // wait for 5 mins for request to be processed - await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)); + // wait for 5 mins for request to be processed + await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)); + await page.reload(); + console.log("Page reloaded"); + // wait for 5 mins for request to be processed + await new Promise((resolve) => setTimeout(resolve, 5 * 60 * 1000)); - // take screenshot - var screenshotPath = path.join( - screenshotDirectory, - `${luxon.DateTime.now().toMillis()}.png` - ); - await page.screenshot({ path: screenshotPath, fullPage: true }); - - // download latest report - await page.waitForSelector("div._2zs6hel0"); - - // Select all divs with the class _2zs6hel0 - const divs = await page.$$("div._2zs6hel0"); - - console.log(`Found ${divs.length} Buttons`); - - const downloadFolderPath = path.resolve( - config[environment].temu_orders_path, - `unprocessed/` - ); - - // download the latest report - if (divs.length > 1) { - generateTheDownloadPath(page, downloadFolderPath); - console.log("Clicking On download Button"); - await new Promise((resolve) => setTimeout(resolve, 10 * 1000)); // take screenshot var screenshotPath = path.join( screenshotDirectory, `${luxon.DateTime.now().toMillis()}.png` ); await page.screenshot({ path: screenshotPath, fullPage: true }); - // wait 600 seconds - await new Promise((resolve) => setTimeout(resolve, 60 * 1000)); - await divs[0].click(); + + // download latest report + await page.waitForSelector("div._2zs6hel0"); + + // Select all divs with the class _2zs6hel0 + const divs = await page.$$("div._2zs6hel0"); + + console.log(`Found ${divs.length} Buttons`); + + const downloadFolderPath = path.resolve( + config[environment].temu_orders_path, + `unprocessed/` + ); + + // download the latest report + if (divs.length > 1) { + generateTheDownloadPath(page, downloadFolderPath); + console.log("Clicking On download Button"); + await new Promise((resolve) => setTimeout(resolve, 10 * 1000)); + // take screenshot + var screenshotPath = path.join( + screenshotDirectory, + `${luxon.DateTime.now().toMillis()}.png` + ); + await page.screenshot({ path: screenshotPath, fullPage: true }); + // wait 600 seconds + await new Promise((resolve) => setTimeout(resolve, 60 * 1000)); + await divs[0].click(); + } + + // take screenshot + var screenshotPath = path.join( + screenshotDirectory, + `${luxon.DateTime.now().toMillis()}.png` + ); + await page.screenshot({ path: screenshotPath, fullPage: true }); + + // wait 60 seconds + await new Promise((resolve) => setTimeout(resolve, 30 * 1000)); + + // generate json from excel mark it processed + const unprocessedFolderPath = path.join( + config[environment].temu_orders_path, + "unprocessed" + ); + } catch (e) { + emailUtils.notify( `Sync Temu Orders`, e.message ); } - // take screenshot - var screenshotPath = path.join( - screenshotDirectory, - `${luxon.DateTime.now().toMillis()}.png` - ); - await page.screenshot({ path: screenshotPath, fullPage: true }); - - // wait 60 seconds - await new Promise((resolve) => setTimeout(resolve, 30 * 1000)); - - // generate json from excel mark it processed - const unprocessedFolderPath = path.join( - config[environment].temu_orders_path, - "unprocessed" - ); - // Function to read Excel files and convert to JSON const convertExcelToJson = () => { fs.readdir(unprocessedFolderPath, (err, files) => { @@ -285,7 +295,11 @@ const utils = require("./utils"); }; convertExcelToJson(); - console.log(`==========< ENDED ${utils.getPakistanStandardTime(luxon.DateTime.now())} >==========`); + console.log( + `==========< ENDED ${utils.getPakistanStandardTime( + luxon.DateTime.now() + )} >==========` + ); await page.close(); await browser.close(); })(); diff --git a/sync-shipping-rates.js b/sync-shipping-rates.js index 0fd45ac..7f92f09 100644 --- a/sync-shipping-rates.js +++ b/sync-shipping-rates.js @@ -7,6 +7,7 @@ const path = require("path"); const dotenv = require("dotenv").config({ path: __dirname + "/.env" }); const utils = require("./utils"); +const emailUtils = require("./email-utils"); (async function () { console.log(`===========< STARTED ${utils.getPakistanStandardTime(luxon.DateTime.now())} >=========`); @@ -21,13 +22,13 @@ const utils = require("./utils"); let rates = []; const email = utils.decryptString( - process.env["temu-email"], + process.env["temu-personal-email"], cryptoConfig.algo, cryptoConfig.key, cryptoConfig.iv ); const password = utils.decryptString( - process.env["temu-password"], + process.env["temu-personal-password"], cryptoConfig.algo, cryptoConfig.key, cryptoConfig.iv @@ -536,69 +537,77 @@ const utils = require("./utils"); // get orders if (orders_list.length > 0) { - // goto every order page - for (const [index, order] of orders_list.entries()) { - console.log( - `Syncing Order ${order} ( ${index + 1} / ${orders_list.length} )` - ); + try { + // goto every order page + for (const [index, order] of orders_list.entries()) { + console.log( + `Syncing Order ${order} ( ${index + 1} / ${orders_list.length} )` + ); - // try login - await utils.tryTemuLogin(page, email, password, loginPage); - await new Promise((resolve) => setTimeout(resolve, 2000)); + // try login + await utils.tryTemuLogin(page, email, password, loginPage); + await new Promise((resolve) => setTimeout(resolve, 2000)); - const orderPage = utils.getTemuOrderPage(order); - await page.goto(orderPage, { - waitUntil: ["domcontentloaded"], - }); - await new Promise((resolve) => setTimeout(resolve, 1000)); + const orderPage = utils.getTemuOrderPage(order); + await page.goto(orderPage, { + waitUntil: ["domcontentloaded"], + }); + await new Promise((resolve) => setTimeout(resolve, 1000)); - // check for buy shipping button - const buyShippingSelector = "div._3yOxLjm0._2pgGmJ7w.IoqjAtdZ"; - const buyShippingBtn = await page.$(buyShippingSelector); - if (!buyShippingBtn) { - console.log("No Buy Shipping Button found"); - continue; + // check for buy shipping button + const buyShippingSelector = "div._3yOxLjm0._2pgGmJ7w.IoqjAtdZ"; + const buyShippingBtn = await page.$(buyShippingSelector); + if (!buyShippingBtn) { + console.log("No Buy Shipping Button found"); + continue; + } + + const responsePromise = checkShippingRates(page, 10_000); + // button exist + await buyShippingBtn.click(); + console.log("Clicking on Buy Shipping Button"); + + let orderShippingRates = await responsePromise; + + await new Promise((resolve) => setTimeout(resolve, 2 * 1_000)); + + if (utils.isEmpty(orderShippingRates)) { + console.log(`Shipping Rates not found`); + // populate orders details to populate shipping rates + const promise = checkShippingRates(page, 10_000); + await populateDataInFields(page, order); + await new Promise((resolve) => setTimeout(resolve, 2 * 1000)); + orderShippingRates = await promise; + } + // fields are already populate / save the shipping rates + mapResponseToRates(orderShippingRates, order); + + // write the JSON data to a file + const outputFilePath = path.join( + config[environment].temu_orders_shipping_rates, + "/unprocessed", + `${order}.json` + ); + if (rates.length > 1) { + // save to rates to file + await writeToFile(rates, outputFilePath); + } + + // wait 10 seconds + await new Promise((resolve) => setTimeout(resolve, 5 * 1000)); + // reinitialize rates + rates = []; } - - const responsePromise = checkShippingRates(page, 10_000); - // button exist - await buyShippingBtn.click(); - console.log("Clicking on Buy Shipping Button"); - - let orderShippingRates = await responsePromise; - - await new Promise((resolve) => setTimeout(resolve, 2 * 1_000)); - - if (utils.isEmpty(orderShippingRates)) { - console.log(`Shipping Rates not found`); - // populate orders details to populate shipping rates - const promise = checkShippingRates(page, 10_000); - await populateDataInFields(page, order); - await new Promise((resolve) => setTimeout(resolve, 2 * 1000)); - orderShippingRates = await promise; - } - // fields are already populate / save the shipping rates - mapResponseToRates(orderShippingRates, order); - - // write the JSON data to a file - const outputFilePath = path.join( - config[environment].temu_orders_shipping_rates, - "/unprocessed", - `${order}.json` - ); - if (rates.length > 1) { - // save to rates to file - await writeToFile(rates, outputFilePath); - } - - // wait 10 seconds - await new Promise((resolve) => setTimeout(resolve, 5 * 1000)); - // reinitialize rates - rates = []; + } catch (e) { + emailUtils.notify( `Sync Temu Orders Shipping Rates`, e.message ); } } - console.log(`==========< ENDED ${utils.getPakistanStandardTime(luxon.DateTime.now())} >==========`); + console.log( + `==========< ENDED ${utils.getPakistanStandardTime( + luxon.DateTime.now() + )} >==========` + ); await page.close(); await browser.close(); })();