From 6967e53164a80a624dd693dec99a310db2a5cb88 Mon Sep 17 00:00:00 2001 From: Adhiraj Singh Date: Mon, 7 Mar 2022 09:09:08 +0530 Subject: [PATCH] feat: implement product CRUD on MD --- src/Socket/business.ts | 95 +++++++++++++++++++++++++++++++- src/Utils/business.ts | 121 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 201 insertions(+), 15 deletions(-) diff --git a/src/Socket/business.ts b/src/Socket/business.ts index ab7fbe6..e3905c2 100644 --- a/src/Socket/business.ts +++ b/src/Socket/business.ts @@ -1,6 +1,7 @@ -import { SocketConfig } from '../Types' -import { parseCatalogNode, parseCollectionsNode, parseOrderDetailsNode } from '../Utils/business' +import { ProductCreate, ProductUpdate, SocketConfig } from '../Types' +import { parseCatalogNode, parseCollectionsNode, parseOrderDetailsNode, parseProductNode, toProductNode } from '../Utils/business' import { jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary' +import { getBinaryNodeChild } from '../WABinary/generic-utils' import { makeMessagesRecvSocket } from './messages-recv' export const makeBusinessSocket = (config: SocketConfig) => { @@ -141,10 +142,98 @@ export const makeBusinessSocket = (config: SocketConfig) => { return parseOrderDetailsNode(result) } + const productUpdate = async(productId: string, update: ProductUpdate) => { + const editNode = toProductNode(productId, update) + + const result = await query({ + tag: 'iq', + attrs: { + to: S_WHATSAPP_NET, + type: 'set', + xmlns: 'w:biz:catalog' + }, + content: [ + { + tag: 'product_catalog_edit', + attrs: { v: '1' }, + content: [ editNode ] + } + ] + }) + + const productCatalogEditNode = getBinaryNodeChild(result, 'product_catalog_edit') + const productNode = getBinaryNodeChild(productCatalogEditNode, 'product') + + return parseProductNode(productNode) + } + + const productCreate = async(create: ProductCreate) => { + const createNode = toProductNode(undefined, create) + + const result = await query({ + tag: 'iq', + attrs: { + to: S_WHATSAPP_NET, + type: 'set', + xmlns: 'w:biz:catalog' + }, + content: [ + { + tag: 'product_catalog_add', + attrs: { v: '1' }, + content: [ createNode ] + } + ] + }) + + const productCatalogAddNode = getBinaryNodeChild(result, 'product_catalog_add') + const productNode = getBinaryNodeChild(productCatalogAddNode, 'product') + + return parseProductNode(productNode) + } + + const productDelete = async(productIds: string[]) => { + const result = await query({ + tag: 'iq', + attrs: { + to: S_WHATSAPP_NET, + type: 'set', + xmlns: 'w:biz:catalog' + }, + content: [ + { + tag: 'product_catalog_delete', + attrs: { v: '1' }, + content: productIds.map( + id => ({ + tag: 'product', + attrs: { }, + content: [ + { + tag: 'id', + attrs: { }, + content: Buffer.from(id) + } + ] + }) + ) + } + ] + }) + + const productCatalogDelNode = getBinaryNodeChild(result, 'product_catalog_delete') + return { + deleted: +productCatalogDelNode.attrs.deleted_count + } + } + return { ...sock, + getOrderDetails, getCatalog, getCollections, - getOrderDetails, + productCreate, + productDelete, + productUpdate } } \ No newline at end of file diff --git a/src/Utils/business.ts b/src/Utils/business.ts index b2725cb..37b935d 100644 --- a/src/Utils/business.ts +++ b/src/Utils/business.ts @@ -1,5 +1,5 @@ -import { CatalogCollection, CatalogStatus, OrderDetails, OrderProduct, Product } from '../Types' -import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString } from '../WABinary' +import { CatalogCollection, CatalogStatus, OrderDetails, OrderProduct, Product, ProductCreate, ProductUpdate } from '../Types' +import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString } from '../WABinary' export const parseCatalogNode = (node: BinaryNode) => { const catalogNode = getBinaryNodeChild(node, 'product_catalog') @@ -11,7 +11,7 @@ export const parseCollectionsNode = (node: BinaryNode) => { const collectionsNode = getBinaryNodeChild(node, 'collections') const collections = getBinaryNodeChildren(collectionsNode, 'collection').map( collectionNode => { - const id = parseCatalogId(collectionNode) + const id = getBinaryNodeChildString(collectionNode, 'id') const name = getBinaryNodeChildString(collectionNode, 'name') const products = getBinaryNodeChildren(collectionNode, 'product').map(parseProductNode) @@ -35,7 +35,7 @@ export const parseOrderDetailsNode = (node: BinaryNode) => { productNode => { const imageNode = getBinaryNodeChild(productNode, 'image') return { - id: parseCatalogId(productNode), + id: getBinaryNodeChildString(productNode, 'id'), name: getBinaryNodeChildString(productNode, 'name'), imageUrl: getBinaryNodeChildString(imageNode, 'url'), price: +getBinaryNodeChildString(productNode, 'price'), @@ -58,9 +58,112 @@ export const parseOrderDetailsNode = (node: BinaryNode) => { return orderDetails } -const parseProductNode = (productNode: BinaryNode) => { +export const toProductNode = (productId: string | undefined, product: ProductCreate | ProductUpdate) => { + const attrs: BinaryNode['attrs'] = { } + const content: BinaryNode[] = [ ] + + if(typeof productId !== 'undefined') { + content.push({ + tag: 'id', + attrs: { }, + content: Buffer.from(productId) + }) + } + + if(typeof product.name !== 'undefined') { + content.push({ + tag: 'name', + attrs: { }, + content: Buffer.from(product.name) + }) + } + + if(typeof product.description !== 'undefined') { + content.push({ + tag: 'description', + attrs: { }, + content: Buffer.from(product.description) + }) + } + + if(typeof product.retailerId !== 'undefined') { + content.push({ + tag: 'retailer_id', + attrs: { }, + content: Buffer.from(product.retailerId) + }) + } + + if(product.imageUrls.length) { + content.push({ + tag: 'media', + attrs: { }, + content: product.imageUrls.map( + url => ({ + tag: 'image', + attrs: { }, + content: [ + { + tag: 'url', + attrs: { }, + content: Buffer.from(url) + } + ] + }) + ) + }) + } + + if(typeof product.price !== 'undefined') { + content.push({ + tag: 'price', + attrs: { }, + content: Buffer.from(product.price.toString()) + }) + } + + if(typeof product.currency !== 'undefined') { + content.push({ + tag: 'currency', + attrs: { }, + content: Buffer.from(product.currency) + }) + } + + if('originCountryCode' in product) { + if(typeof product.originCountryCode === 'undefined') { + attrs.compliance_category = 'COUNTRY_ORIGIN_EXEMPT' + } else { + content.push({ + tag: 'compliance_info', + attrs: { }, + content: [ + { + tag: 'country_code_origin', + attrs: { }, + content: Buffer.from(product.originCountryCode) + } + ] + }) + } + } + + + if(typeof product.isHidden !== 'undefined') { + attrs.is_hidden = product.isHidden.toString() + } + + const node: BinaryNode = { + tag: 'product', + attrs, + content + } + return node +} + +export const parseProductNode = (productNode: BinaryNode) => { const isHidden = productNode.attrs.is_hidden === 'true' - const id = parseCatalogId(productNode) + const id = getBinaryNodeChildString(productNode, 'id') const mediaNode = getBinaryNodeChild(productNode, 'media') const statusInfoNode = getBinaryNodeChild(productNode, 'status_info') @@ -98,10 +201,4 @@ const parseStatusInfo = (mediaNode: BinaryNode): CatalogStatus => { status: getBinaryNodeChildString(node, 'status'), canAppeal: getBinaryNodeChildString(node, 'can_appeal') === 'true', } -} - -const parseCatalogId = (node: BinaryNode) => { - const idNode = getBinaryNodeChildBuffer(node, 'id') - const id = Buffer.from(idNode).readBigUInt64LE().toString() - return id } \ No newline at end of file