diff --git a/src/api/controllers/chat.controller.ts b/src/api/controllers/chat.controller.ts index 207d8ba5..8c922f11 100644 --- a/src/api/controllers/chat.controller.ts +++ b/src/api/controllers/chat.controller.ts @@ -3,6 +3,8 @@ import { BlockUserDto, DeleteMessage, getBase64FromMediaMessageDto, + getCatalogDto, + getCollectionsDto, MarkChatUnreadDto, NumberDto, PrivacySettingDto, @@ -109,4 +111,12 @@ export class ChatController { public async blockUser({ instanceName }: InstanceDto, data: BlockUserDto) { return await this.waMonitor.waInstances[instanceName].blockUser(data); } + + public async fetchCatalog({ instanceName }: InstanceDto, data: getCatalogDto) { + return await this.waMonitor.waInstances[instanceName].fetchCatalog(instanceName, data); + } + + public async fetchCatalogCollections({ instanceName }: InstanceDto, data: getCollectionsDto) { + return await this.waMonitor.waInstances[instanceName].fetchCatalogCollections(instanceName, data); + } } diff --git a/src/api/dto/chat.dto.ts b/src/api/dto/chat.dto.ts index 00da7fdd..1693165e 100644 --- a/src/api/dto/chat.dto.ts +++ b/src/api/dto/chat.dto.ts @@ -126,3 +126,14 @@ export class BlockUserDto { number: string; status: 'block' | 'unblock'; } + +export class getCatalogDto { + number?: string; + limit?: number; + cursor?: string; +} + +export class getCollectionsDto { + number?: string; + limit?: number; +} diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 0d809533..57197e17 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -4,6 +4,8 @@ import { BlockUserDto, DeleteMessage, getBase64FromMediaMessageDto, + getCatalogDto, + getCollectionsDto, LastMessage, MarkChatUnreadDto, NumberBusiness, @@ -91,6 +93,7 @@ import makeWASocket, { BufferedEventData, BufferJSON, CacheStore, + CatalogCollection, Chat, ConnectionState, Contact, @@ -100,6 +103,7 @@ import makeWASocket, { fetchLatestBaileysVersion, generateWAMessageFromContent, getAggregateVotesInPollMessage, + GetCatalogOptions, getContentType, getDevice, GroupMetadata, @@ -113,6 +117,7 @@ import makeWASocket, { MiscMessageGenerationOptions, ParticipantAction, prepareWAMessageMedia, + Product, proto, UserFacingSocketConfig, WABrowserDescription, @@ -4628,4 +4633,118 @@ export class BaileysStartupService extends ChannelStartupService { return response; } + + //Catalogs and collections + public async fetchCatalog(instanceName: string, data: getCatalogDto) { + const jid = data.number ? createJid(data.number) : this.client?.user?.id; + const limit = data.limit || 10; + const cursor = data.cursor || null; + + const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + + if (!onWhatsapp.exists) { + throw new BadRequestException(onWhatsapp); + } + + try { + const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + const business = await this.fetchBusinessProfile(info?.jid); + const catalog = await this.getCatalog({ jid: info?.jid, limit, cursor }); + + return { + wuid: info?.jid || jid, + name: info?.name, + numberExists: info?.exists, + isBusiness: business.isBusiness, + catalogLength: catalog?.products.length, + catalog: catalog?.products, + }; + } catch (error) { + console.log(error); + return { + wuid: jid, + name: null, + isBusiness: false, + }; + } + } + + public async getCatalog({ + jid, + limit, + cursor, + }: GetCatalogOptions): Promise<{ products: Product[]; nextPageCursor: string | undefined }> { + try { + jid = jid ? createJid(jid) : this.instance.wuid; + + const catalog = await this.client.getCatalog({ jid, limit: limit, cursor: cursor }); + + if (!catalog) { + return { + products: undefined, + nextPageCursor: undefined, + }; + } + + return catalog; + } catch (error) { + throw new InternalServerErrorException('Error getCatalog', error.toString()); + } + } + + public async fetchCatalogCollections(instanceName: string, data: getCollectionsDto) { + const jid = data.number ? createJid(data.number) : this.client?.user?.id; + const limit = data.limit || 10; + + const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + + if (!onWhatsapp.exists) { + throw new BadRequestException(onWhatsapp); + } + + try { + const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + const business = await this.fetchBusinessProfile(info?.jid); + const catalogCollections = await this.getCollections(info?.jid, limit); + + return { + wuid: info?.jid || jid, + name: info?.name, + numberExists: info?.exists, + isBusiness: business.isBusiness, + catalogLength: catalogCollections?.length, + catalogCollections: catalogCollections, + }; + } catch (error) { + console.log(error); + return { + wuid: jid, + name: null, + isBusiness: false, + }; + } + } + + public async getCollections(jid?: string | undefined, limit?: number): Promise { + try { + jid = jid ? createJid(jid) : this.instance.wuid; + + const result = await this.client.getCollections(jid, limit); + + if (!result) { + return [ + { + id: undefined, + name: undefined, + products: [], + status: undefined, + }, + ]; + } + + return result.collections; + } catch (error) { + throw new InternalServerErrorException('Error getCatalog', error.toString()); + } + } } diff --git a/src/api/routes/chat.router.ts b/src/api/routes/chat.router.ts index 20126c1a..aac9fe39 100644 --- a/src/api/routes/chat.router.ts +++ b/src/api/routes/chat.router.ts @@ -22,6 +22,8 @@ import { Contact, Message, MessageUpdate } from '@prisma/client'; import { archiveChatSchema, blockUserSchema, + catalogSchema, + collectionsSchema, contactValidateSchema, deleteMessageSchema, markChatUnreadSchema, @@ -267,6 +269,28 @@ export class ChatRouter extends RouterBroker { }); return res.status(HttpStatus.CREATED).json(response); + }) + + .post(this.routerPath('fetchCatalog'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: catalogSchema, + ClassRef: NumberDto, + execute: (instance, data) => chatController.fetchCatalog(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + + .post(this.routerPath('fetchCollections'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: collectionsSchema, + ClassRef: NumberDto, + execute: (instance, data) => chatController.fetchCatalogCollections(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); }); } diff --git a/src/validate/chat.schema.ts b/src/validate/chat.schema.ts index dba27995..fd324c10 100644 --- a/src/validate/chat.schema.ts +++ b/src/validate/chat.schema.ts @@ -315,3 +315,21 @@ export const profileSchema: JSONSchema7 = { isBusiness: { type: 'boolean' }, }, }; + +export const catalogSchema: JSONSchema7 = { + type: 'object', + properties: { + number: { type: 'string' }, + limit: { type: 'number' }, + cursor: { type: 'string' }, + }, +}; + +export const collectionsSchema: JSONSchema7 = { + type: 'object', + properties: { + number: { type: 'string' }, + limit: { type: 'number' }, + cursor: { type: 'string' }, + }, +};