@@ -33,6 +33,7 @@ import { HandleLabelDto, LabelDto } from '@api/dto/label.dto';
3333import {
3434 Button ,
3535 ContactMessage ,
36+ KeyType ,
3637 MediaMessage ,
3738 Options ,
3839 SendAudioDto ,
@@ -272,7 +273,7 @@ export class BaileysStartupService extends ChannelStartupService {
272273 qrcodeTerminal . generate ( qr , { small : true } , ( qrcode ) =>
273274 this . logger . log (
274275 `\n{ instance: ${ this . instance . name } pairingCode: ${ this . instance . qrcode . pairingCode } , qrcodeCount: ${ this . instance . qrcode . count } }\n` +
275- qrcode ,
276+ qrcode ,
276277 ) ,
277278 ) ;
278279
@@ -1988,9 +1989,7 @@ export class BaileysStartupService extends ChannelStartupService {
19881989
19891990 const prepareMedia = await prepareWAMessageMedia (
19901991 {
1991- [ type ] : isURL ( mediaMessage . media )
1992- ? { url : mediaMessage . media }
1993- : Buffer . from ( mediaMessage . media , 'base64' ) ,
1992+ [ type ] : isURL ( mediaMessage . media ) ? { url : mediaMessage . media } : Buffer . from ( mediaMessage . media , 'base64' ) ,
19941993 } as any ,
19951994 { upload : this . client . waUploadToServer } ,
19961995 ) ;
@@ -2154,7 +2153,7 @@ export class BaileysStartupService extends ChannelStartupService {
21542153 ) ;
21552154 }
21562155
2157- public async ptvMessage ( data : SendPtvDto , file ?: any , isIntegration = false ) {
2156+ public async ptvMessage ( data : SendPtvDto , file ?: any ) {
21582157 const mediaData : SendMediaDto = {
21592158 number : data . number ,
21602159 media : data . video ,
@@ -2230,6 +2229,15 @@ export class BaileysStartupService extends ChannelStartupService {
22302229 ) ;
22312230 }
22322231
2232+ private generateRandomId ( length = 11 ) {
2233+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ;
2234+ let result = '' ;
2235+ for ( let i = 0 ; i < length ; i ++ ) {
2236+ result += characters . charAt ( Math . floor ( Math . random ( ) * characters . length ) ) ;
2237+ }
2238+ return result ;
2239+ }
2240+
22332241 private toJSONString ( button : Button ) : string {
22342242 const toString = ( obj : any ) => JSON . stringify ( obj ) ;
22352243
@@ -2243,6 +2251,49 @@ export class BaileysStartupService extends ChannelStartupService {
22432251 url : button . url ,
22442252 merchant_url : button . url ,
22452253 } ) ,
2254+ pix : ( ) =>
2255+ toString ( {
2256+ currency : button . currency ,
2257+ total_amount : {
2258+ value : 0 ,
2259+ offset : 100 ,
2260+ } ,
2261+ reference_id : this . generateRandomId ( ) ,
2262+ type : 'physical-goods' ,
2263+ order : {
2264+ status : 'pending' ,
2265+ subtotal : {
2266+ value : 0 ,
2267+ offset : 100 ,
2268+ } ,
2269+ order_type : 'ORDER' ,
2270+ items : [
2271+ {
2272+ name : '' ,
2273+ amount : {
2274+ value : 0 ,
2275+ offset : 100 ,
2276+ } ,
2277+ quantity : 0 ,
2278+ sale_amount : {
2279+ value : 0 ,
2280+ offset : 100 ,
2281+ } ,
2282+ } ,
2283+ ] ,
2284+ } ,
2285+ payment_settings : [
2286+ {
2287+ type : 'pix_static_code' ,
2288+ pix_static_code : {
2289+ merchant_name : button . name ,
2290+ key : button . key ,
2291+ key_type : this . mapKeyType . get ( button . keyType ) ,
2292+ } ,
2293+ } ,
2294+ ] ,
2295+ share_payment_status : false ,
2296+ } ) ,
22462297 } ;
22472298
22482299 return json [ button . type ] ?.( ) || '' ;
@@ -2253,74 +2304,69 @@ export class BaileysStartupService extends ChannelStartupService {
22532304 [ 'copy' , 'cta_copy' ] ,
22542305 [ 'url' , 'cta_url' ] ,
22552306 [ 'call' , 'cta_call' ] ,
2307+ [ 'pix' , 'payment_info' ] ,
22562308 ] ) ;
22572309
2258- public async buttonMessage ( data : SendButtonsDto ) {
2259- const generate = await ( async ( ) => {
2260- if ( data ?. thumbnailUrl ) {
2261- return await this . prepareMediaMessage ( {
2262- mediatype : 'image' ,
2263- media : data . thumbnailUrl ,
2264- } ) ;
2265- }
2266- } ) ( ) ;
2267-
2268- const buttons = data . buttons . map ( ( value ) => {
2269- return {
2270- name : this . mapType . get ( value . type ) ,
2271- buttonParamsJson : this . toJSONString ( value ) ,
2272- } ;
2273- } ) ;
2310+ private readonly mapKeyType = new Map < KeyType , string > ( [
2311+ [ 'phone' , 'PHONE' ] ,
2312+ [ 'email' , 'EMAIL' ] ,
2313+ [ 'cpf' , 'CPF' ] ,
2314+ [ 'cnpj' , 'CNPJ' ] ,
2315+ [ 'random' , 'EVP' ] ,
2316+ ] ) ;
22742317
2275- const message : proto . IMessage = {
2276- viewOnceMessage : {
2277- message : {
2278- messageContextInfo : {
2279- deviceListMetadata : { } ,
2280- deviceListMetadataVersion : 2 ,
2281- } ,
2282- interactiveMessage : {
2283- body : {
2284- text : ( ( ) => {
2285- let t = '*' + data . title + '*' ;
2286- if ( data ?. description ) {
2287- t += '\n\n' ;
2288- t += data . description ;
2289- t += '\n' ;
2290- }
2291- return t ;
2292- } ) ( ) ,
2293- } ,
2294- footer : {
2295- text : data ?. footer ,
2296- } ,
2297- header : ( ( ) => {
2298- if ( generate ?. message ?. imageMessage ) {
2299- return {
2300- hasMediaAttachment : ! ! generate . message . imageMessage ,
2301- imageMessage : generate . message . imageMessage ,
2302- } ;
2303- }
2304- } ) ( ) ,
2305- nativeFlowMessage : {
2306- buttons : buttons ,
2307- messageParamsJson : JSON . stringify ( {
2308- from : 'api' ,
2309- templateId : v4 ( ) ,
2310- } ) ,
2318+ public async buttonMessage ( data : SendButtonsDto ) {
2319+ if ( data . buttons . length === 0 ) {
2320+ throw new BadRequestException ( 'At least one button is required' ) ;
2321+ }
2322+ const hasReplyButtons = data . buttons . some ( ( btn ) => btn . type === 'reply' ) ;
2323+
2324+ const hasPixButton = data . buttons . some ( ( btn ) => btn . type === 'pix' ) ;
2325+
2326+ const hasOtherButtons = data . buttons . some ( ( btn ) => btn . type !== 'reply' && btn . type !== 'pix' ) ;
2327+ if ( hasReplyButtons ) {
2328+ if ( data . buttons . length > 3 ) {
2329+ throw new BadRequestException ( 'Maximum of 3 reply buttons allowed' ) ;
2330+ }
2331+ if ( hasOtherButtons ) {
2332+ throw new BadRequestException ( 'Reply buttons cannot be mixed with other button types' ) ;
2333+ }
2334+ }
2335+ if ( hasPixButton ) {
2336+ if ( data . buttons . length > 1 ) {
2337+ throw new BadRequestException ( 'Only one PIX button is allowed' ) ;
2338+ }
2339+ if ( hasOtherButtons ) {
2340+ throw new BadRequestException ( 'PIX button cannot be mixed with other button types' ) ;
2341+ }
2342+ const message : proto . IMessage = {
2343+ viewOnceMessage : {
2344+ message : {
2345+ interactiveMessage : {
2346+ nativeFlowMessage : {
2347+ buttons : [
2348+ {
2349+ name : this . mapType . get ( 'pix' ) ,
2350+ buttonParamsJson : this . toJSONString ( data . buttons [ 0 ] ) ,
2351+ } ,
2352+ ] ,
2353+ messageParamsJson : JSON . stringify ( {
2354+ from : 'api' ,
2355+ templateId : v4 ( ) ,
2356+ } ) ,
2357+ } ,
23112358 } ,
23122359 } ,
23132360 } ,
2314- } ,
2315- } ;
2316-
2317- return await this . sendMessageWithTyping ( data . number , message , {
2318- delay : data ?. delay ,
2319- presence : 'composing' ,
2320- quoted : data ?. quoted ,
2321- mentionsEveryOne : data ?. mentionsEveryOne ,
2322- mentioned : data ?. mentioned ,
2323- } ) ;
2361+ } ;
2362+ return await this . sendMessageWithTyping ( data . number , message , {
2363+ delay : data ?. delay ,
2364+ presence : 'composing' ,
2365+ quoted : data ?. quoted ,
2366+ mentionsEveryOne : data ?. mentionsEveryOne ,
2367+ mentioned : data ?. mentioned ,
2368+ } ) ;
2369+ }
23242370 }
23252371
23262372 public async listMessage ( data : SendListDto ) {
0 commit comments