From 5177a257cf669b85a1cfdd86eca4b39596ff2683 Mon Sep 17 00:00:00 2001 From: renjop <16737036+renjop@users.noreply.github.com> Date: Mon, 31 May 2021 18:46:43 -0600 Subject: [PATCH] feat: Get Orders and Products (#612) * - Get products and orders * - Get products and orders * - Eslint fixes * - Eslint fixes * allow downloading media for products * products and orders work on normal accounts Co-authored-by: Renato Jop Co-authored-by: Pedro Lopez Co-authored-by: Pedro S. Lopez --- index.d.ts | 100 +++++++++++++++++++++++++++++- index.js | 2 +- src/structures/Message.js | 49 ++++++++++++++- src/structures/Order.js | 52 ++++++++++++++++ src/structures/Product.js | 68 ++++++++++++++++++++ src/structures/ProductMetadata.js | 25 ++++++++ src/structures/index.js | 4 +- src/util/Constants.js | 2 + src/util/Injected.js | 17 +++++ 9 files changed, 314 insertions(+), 5 deletions(-) create mode 100644 src/structures/Order.js create mode 100644 src/structures/Product.js create mode 100644 src/structures/ProductMetadata.js diff --git a/index.d.ts b/index.d.ts index fca2864..f68bc34 100644 --- a/index.d.ts +++ b/index.d.ts @@ -413,6 +413,8 @@ declare namespace WAWebJS { CONTACT_CARD = 'vcard', CONTACT_CARD_MULTI = 'multi_vcard', REVOKED = 'revoked', + ORDER = 'order', + PRODUCT = 'product', UNKNOWN = 'unknown', } @@ -521,7 +523,16 @@ declare namespace WAWebJS { type: MessageTypes, /** Links included in the message. */ links: string[], - + /** Order ID */ + orderId: string, + /** title */ + title?: string, + /** description*/ + description?: string, + /** Business Owner JID */ + businessOwnerJid?: string, + /** Product JID */ + productId?: string, /** Deletes the message from the chat */ delete: (everyone?: boolean) => Promise, /** Downloads and returns the attatched message media */ @@ -549,7 +560,11 @@ declare namespace WAWebJS { /** Unstar this message */ unstar: () => Promise, /** Get information about message delivery statuso */ - getInfo: () => Promise + getInfo: () => Promise, + /** + * Gets the order associated with a given message + */ + getOrder: () => Order, } /** ID that represents a message */ @@ -917,6 +932,87 @@ declare namespace WAWebJS { /** Makes the bot leave the group */ leave: () => Promise; } + + /** + * Represents the metadata associated with a given product + * + */ + export interface ProductMetadata { + /** Product Id */ + id: string, + /** Product Name */ + name: string, + /** Product Description */ + description: string, + /** Retailer ID */ + retailer_id?: string + } + + /** + * Represents a Product on Whatsapp + * @example + * { + * "id": "123456789", + * "price": "150000", + * "thumbnailId": "123456789", + * "thumbnailUrl": "https://mmg.whatsapp.net", + * "currency": "GTQ", + * "name": "Store Name", + * "quantity": 1 + * } + */ + export interface Product { + /** Product Id */ + id: string, + /** Price */ + price?: string, + /** Product Thumbnail*/ + thumbnailUrl: string, + /** Currency */ + currency: string, + /** Product Name */ + name: string, + /** Product Quantity*/ + quantity: number, + /** Gets the Product metadata */ + getData: () => Promise + } + + /** + * Represents a Order on WhatsApp + * + * @example + * { + * "products": [ + * { + * "id": "123456789", + * "price": "150000", + * "thumbnailId": "123456789", + * "thumbnailUrl": "https://mmg.whatsapp.net", + * "currency": "GTQ", + * "name": "Store Name", + * "quantity": 1 + * } + * ], + * "subtotal": "150000", + * "total": "150000", + * "currency": "GTQ", + * "createdAt": 1610136796, + * "sellerJid": "55555555@s.whatsapp.net" + * } + */ + export interface Order { + /** List of products*/ + products: Array, + /** Order Subtotal */ + subtotal: string, + /** Order Total */ + total: string, + /** Order Currency */ + currency: string, + /** Order Created At*/ + createdAt: number; + } } export = WAWebJS diff --git a/index.js b/index.js index a67d16e..44ad5c8 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,6 @@ module.exports = { BusinessContact: require('./src/structures/BusinessContact'), ClientInfo: require('./src/structures/ClientInfo'), Location: require('./src/structures/Location'), - + ProductMetadata: require('./src/structures/ProductMetadata'), ...Constants }; diff --git a/src/structures/Message.js b/src/structures/Message.js index 82cd9d3..918d55e 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -3,6 +3,7 @@ const Base = require('./Base'); const MessageMedia = require('./MessageMedia'); const Location = require('./Location'); +const Order = require('./Order'); const { MessageTypes } = require('../util/Constants'); /** @@ -40,7 +41,7 @@ class Message extends Base { * Indicates if the message has media available for download * @type {boolean} */ - this.hasMedia = data.clientUrl || data.deprecatedMms3Url ? true : false; + this.hasMedia = data.clientUrl || data.deprecatedMms3Url; /** * Message content @@ -139,6 +140,37 @@ class Message extends Base { this.mentionedIds = data.mentionedJidList; } + /** + * Order ID for message type ORDER + * @type {string} + */ + this.orderId = data.orderId ? data.orderId : undefined; + /** + * Order Token for message type ORDER + * @type {string} + */ + this.token = data.token ? data.token : undefined; + + /** Title */ + if (data.title) { + this.title = data.title; + } + + /** Description */ + if (data.description) { + this.description = data.description; + } + + /** Business Owner JID */ + if (data.businessOwnerJid) { + this.businessOwnerJid = data.businessOwnerJid; + } + + /** Product ID */ + if (data.productId) { + this.productId = data.productId; + } + /** * Links included in the message. * @type {Array} @@ -342,6 +374,21 @@ class Message extends Base { return info; } + + /** + * Gets the order associated with a given message + * @return {Promise} + */ + async getOrder() { + if (this.type === MessageTypes.ORDER) { + const result = await this.client.pupPage.evaluate((orderId, token) => { + return window.WWebJS.getOrderDetail(orderId, token); + }, this.orderId, this.token); + if (!result) return undefined; + return new Order(this.client, result); + } + return undefined; + } } module.exports = Message; diff --git a/src/structures/Order.js b/src/structures/Order.js new file mode 100644 index 0000000..0842625 --- /dev/null +++ b/src/structures/Order.js @@ -0,0 +1,52 @@ +'use strict'; + +const Base = require('./Base'); +const Product = require('./Product'); + +/** + * Represents a Order on WhatsApp + * @extends {Base} + */ +class Order extends Base { + constructor(client, data) { + super(client); + + if (data) this._patch(data); + } + + _patch(data) { + /** + * List of products + * @type {Array} + */ + if (data.products) { + this.products = data.products.map(product => new Product(this.client, product)); + } + /** + * Order Subtotal + * @type {string} + */ + this.subtotal = data.subtotal; + /** + * Order Total + * @type {string} + */ + this.total = data.total; + /** + * Order Currency + * @type {string} + */ + this.currency = data.currency; + /** + * Order Created At + * @type {number} + */ + this.createdAt = data.createdAt; + + return super._patch(data); + } + + +} + +module.exports = Order; \ No newline at end of file diff --git a/src/structures/Product.js b/src/structures/Product.js new file mode 100644 index 0000000..f208b35 --- /dev/null +++ b/src/structures/Product.js @@ -0,0 +1,68 @@ +'use strict'; + +const Base = require('./Base'); +const ProductMetadata = require('./ProductMetadata'); + +/** + * Represents a Product on WhatsAppBusiness + * @extends {Base} + */ +class Product extends Base { + constructor(client, data) { + super(client); + + if (data) this._patch(data); + } + + _patch(data) { + /** + * Product ID + * @type {string} + */ + this.id = data.id; + /** + * Price + * @type {string} + */ + this.price = data.price ? data.price : ''; + /** + * Product Thumbnail + * @type {string} + */ + this.thumbnailUrl = data.thumbnailUrl; + /** + * Currency + * @type {string} + */ + this.currency = data.currency; + /** + * Product Name + * @type {string} + */ + this.name = data.name; + /** + * Product Quantity + * @type {number} + */ + this.quantity = data.quantity; + /** Product metadata */ + this.data = null; + return super._patch(data); + } + + async getData() { + if (this.data === null) { + let result = await this.client.pupPage.evaluate((productId) => { + return window.WWebJS.getProductMetadata(productId); + }, this.id); + if (!result) { + this.data = undefined; + } else { + this.data = new ProductMetadata(this.client, result); + } + } + return this.data; + } +} + +module.exports = Product; \ No newline at end of file diff --git a/src/structures/ProductMetadata.js b/src/structures/ProductMetadata.js new file mode 100644 index 0000000..e134077 --- /dev/null +++ b/src/structures/ProductMetadata.js @@ -0,0 +1,25 @@ +const Base = require('./Base'); + +class ProductMetadata extends Base { + constructor(client, data) { + super(client); + + if (data) this._patch(data); + } + + _patch(data) { + /** Product ID */ + this.id = data.id; + /** Retailer ID */ + this.retailer_id = data.retailer_id; + /** Product Name */ + this.name = data.name; + /** Product Description */ + this.description = data.description; + + return super._patch(data); + } + +} + +module.exports = ProductMetadata; \ No newline at end of file diff --git a/src/structures/index.js b/src/structures/index.js index c1da5ba..b9381c3 100644 --- a/src/structures/index.js +++ b/src/structures/index.js @@ -11,5 +11,7 @@ module.exports = { PrivateChat: require('./PrivateChat'), PrivateContact: require('./PrivateContact'), GroupNotification: require('./GroupNotification'), - Label: require('./Label.js') + Label: require('./Label.js'), + Order: require('./Order'), + Product: require('./Product') }; \ No newline at end of file diff --git a/src/util/Constants.js b/src/util/Constants.js index a98266f..3fb851b 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -68,7 +68,9 @@ exports.MessageTypes = { LOCATION: 'location', CONTACT_CARD: 'vcard', CONTACT_CARD_MULTI: 'multi_vcard', + ORDER: 'order', REVOKED: 'revoked', + PRODUCT: 'product', UNKNOWN: 'unknown' }; diff --git a/src/util/Injected.js b/src/util/Injected.js index a613bfd..61e5554 100644 --- a/src/util/Injected.js +++ b/src/util/Injected.js @@ -32,6 +32,9 @@ exports.ExposeStore = (moduleRaidStr) => { window.Store.Sticker = window.mR.findModule('Sticker')[0].default.Sticker; window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default; window.Store.Label = window.mR.findModule('LabelCollection')[0].default; + window.Store.QueryOrder = window.mR.findModule('queryOrder')[0]; + window.Store.QueryProduct = window.mR.findModule('queryProduct')[0]; + }; exports.LoadUtils = () => { @@ -458,6 +461,20 @@ exports.LoadUtils = () => { const chat = await window.WWebJS.getChat(chatId); return (chat.labels || []).map(id => window.WWebJS.getLabel(id)); }; + + window.WWebJS.getOrderDetail = async (orderId, token) => { + return window.Store.QueryOrder.queryOrder(orderId, 80, 80, token); + }; + + window.WWebJS.getProductMetadata = async (productId) => { + let sellerId = window.Store.Conn.wid; + let product = await window.Store.QueryProduct.queryProduct(sellerId, productId); + if (product && product.data) { + return product.data; + } + + return undefined; + }; }; exports.MarkAllRead = () => {