Skip to content

Conversation

@victoreduardo
Copy link
Contributor

@victoreduardo victoreduardo commented Nov 13, 2025

πŸ“‹ Description

handle with interactive button message for pix

πŸ”— Related Issue

πŸ§ͺ Type of Change

  • πŸ› Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • πŸ’₯ Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • πŸ“š Documentation update
  • πŸ”§ Refactoring (no functional changes)
  • ⚑ Performance improvement
  • 🧹 Code cleanup
  • πŸ”’ Security fix

πŸ§ͺ Testing

  • Manual testing completed
  • Functionality verified in development environment
  • No breaking changes introduced
  • Tested with different connection types (if applicable)

πŸ“Έ Screenshots (if applicable)

Screenshot 2025-11-13 at 10 02 42

βœ… Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have manually tested my changes thoroughly
  • I have verified the changes work with different scenarios
  • Any dependent changes have been merged and published

πŸ“ Additional Notes

Summary by Sourcery

Enable handling of interactive button messages by detecting Pix payment buttons, parsing their parameters, and sending formatted Pix payment details back to the conversation.

New Features:

  • Detect and process interactive button messages containing Pix payment information
  • Extract Pix static code parameters (merchant name, key type, and key) from button payloads and format them for messaging

Enhancements:

  • Add a utility method to identify interactive button messages in the chat flow
  • Integrate the new button detection into the main message handling pipeline

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 13, 2025

Reviewer's Guide

This PR enhances the ChatwootService to recognize and handle interactive button messages, specifically extracting PIX static code payment details from buttons and sending formatted PIX information back to the user.

Sequence diagram for handling interactive button message with PIX payment

sequenceDiagram
    actor User
    participant ChatwootService
    participant Logger
    participant MessageSender
    User->>ChatwootService: Sends interactive button message
    ChatwootService->>ChatwootService: isInteractiveButtonMessage()
    ChatwootService->>Logger: info('is Interactive Button Message')
    ChatwootService->>ChatwootService: Extract buttonParams & payment_settings
    alt Button is payment_info & type is pix_static_code
        ChatwootService->>ChatwootService: Format PIX info content
        ChatwootService->>MessageSender: createMessage(..., content, ...)
        MessageSender-->>ChatwootService: Message sent
        ChatwootService->>Logger: warn('message not sent')
    else Button not mapped
        ChatwootService->>Logger: warn('Interactive Button Message not mapped')
    end
Loading

Class diagram for updated ChatwootService methods

classDiagram
    class ChatwootService {
        - isInteractiveButtonMessage(messageType: string, message: any): boolean
        - getAdsMessage(msg: any): AdsMessage
        + createMessage(...): Promise<any>
        ...
    }
    class AdsMessage {
        title: string
        body: string
        thumbnailUrl: string
    }
    ChatwootService --> AdsMessage
Loading

File-Level Changes

Change Details Files
Add helper and update message validation to include interactive button messages
  • Introduce isInteractiveButtonMessage method to detect interactive messages with buttons
  • Modify existing message existence check to bypass warning when interactive button messages are present
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts
Implement processing logic for PIX payment interactive buttons
  • Log received interactive buttons and iterate over them
  • Parse buttonParamsJson and extract payment_settings for PIX static code
  • Map PIX key types to user-friendly labels and normalize phone keys
  • Compose and send a formatted message with merchant name and PIX key
  • Add warnings for unmapped buttons or failed message sends
src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Consider refactoring the interactive button handling (including JSON parsing and PIX logic) into a separate helper or service to keep ChatwootService concise and improve testability.
  • Wrap the JSON.parse call for button.buttonParamsJson in a try/catch block to prevent unhandled exceptions if the payload is malformed.
  • Extract the PIX message construction (merchant name, key formatting, and type mapping) into a dedicated helper function to improve readability and avoid inline complexity.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider refactoring the interactive button handling (including JSON parsing and PIX logic) into a separate helper or service to keep ChatwootService concise and improve testability.
- Wrap the JSON.parse call for button.buttonParamsJson in a try/catch block to prevent unhandled exceptions if the payload is malformed.
- Extract the PIX message construction (merchant name, key formatting, and type mapping) into a dedicated helper function to improve readability and avoid inline complexity.

## Individual Comments

### Comment 1
<location> `src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts:2137` </location>
<code_context>
+            const buttonParams = JSON.parse(button.buttonParamsJson);
+            const paymentSettings = buttonParams.payment_settings;
+
+            if (button.name === 'payment_info' && paymentSettings[0].type === 'pix_static_code') {
+              const pixSettings = paymentSettings[0].pix_static_code;
+              const pixKeyType = (() => {
</code_context>

<issue_to_address>
**issue (bug_risk):** Accessing paymentSettings[0] assumes paymentSettings is a non-empty array.

Add a check to ensure paymentSettings exists and is not empty before accessing paymentSettings[0].
</issue_to_address>

### Comment 2
<location> `src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts:2151-2152` </location>
<code_context>
+                    return pixSettings.key_type;
+                }
+              })();
+              const pixKey = pixSettings.key_type === 'PHONE' ? pixSettings.key.replace('+55', '') : pixSettings.key;
+              const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`;
+
</code_context>

<issue_to_address>
**suggestion:** Replacing '+55' may not handle all phone formats.

This approach may fail if the phone key does not start with '+55'. Please ensure the phone format is validated or normalized before performing the replacement.

```suggestion
              const normalizePhoneKey = (key: string) => {
                // Remove all non-digit characters
                const digits = key.replace(/\D/g, '');
                // If it starts with 55 and has 13 digits, remove the country code
                if (digits.length === 13 && digits.startsWith('55')) {
                  return digits.slice(2);
                }
                // If it already has 11 digits (standard BR phone), return as is
                if (digits.length === 11) {
                  return digits;
                }
                // Otherwise, return the original key for manual review
                return key;
              };
              const pixKey = pixSettings.key_type === 'PHONE' ? normalizePhoneKey(pixSettings.key) : pixSettings.key;
              const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`;
```
</issue_to_address>

### Comment 3
<location> `src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts:2154-2165` </location>
<code_context>
+              const pixKey = pixSettings.key_type === 'PHONE' ? pixSettings.key.replace('+55', '') : pixSettings.key;
+              const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`;
+
+              const send = await this.createMessage(
+                instance,
+                getConversation,
</code_context>

<issue_to_address>
**suggestion (bug_risk):** The return value of createMessage is checked only for falsy values.

If createMessage throws an error, it will bypass the warning. Wrap the call in try/catch to ensure errors are properly handled.

```suggestion
              let send;
              try {
                send = await this.createMessage(
                  instance,
                  getConversation,
                  content,
                  messageType,
                  false,
                  [],
                  body,
                  'WAID:' + body.key.id,
                  quotedMsg,
                );
                if (!send) this.logger.warn('message not sent');
              } catch (error) {
                this.logger.warn('message not sent due to error', error);
              }
```
</issue_to_address>

### Comment 4
<location> `src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts:2130` </location>
<code_context>
          const buttons = body.message.interactiveMessage.nativeFlowMessage.buttons;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Prefer object destructuring when accessing and using properties. ([`use-object-destructuring`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/use-object-destructuring))

```suggestion
          const {buttons} = body.message.interactiveMessage.nativeFlowMessage;
```

<br/><details><summary>Explanation</summary>Object destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the [Airbnb Javascript Style Guide](https://airbnb.io/javascript/#destructuring--object)
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.

const buttonParams = JSON.parse(button.buttonParamsJson);
const paymentSettings = buttonParams.payment_settings;

if (button.name === 'payment_info' && paymentSettings[0].type === 'pix_static_code') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Accessing paymentSettings[0] assumes paymentSettings is a non-empty array.

Add a check to ensure paymentSettings exists and is not empty before accessing paymentSettings[0].

Comment on lines +2151 to +2152
const pixKey = pixSettings.key_type === 'PHONE' ? pixSettings.key.replace('+55', '') : pixSettings.key;
const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Replacing '+55' may not handle all phone formats.

This approach may fail if the phone key does not start with '+55'. Please ensure the phone format is validated or normalized before performing the replacement.

Suggested change
const pixKey = pixSettings.key_type === 'PHONE' ? pixSettings.key.replace('+55', '') : pixSettings.key;
const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`;
const normalizePhoneKey = (key: string) => {
// Remove all non-digit characters
const digits = key.replace(/\D/g, '');
// If it starts with 55 and has 13 digits, remove the country code
if (digits.length === 13 && digits.startsWith('55')) {
return digits.slice(2);
}
// If it already has 11 digits (standard BR phone), return as is
if (digits.length === 11) {
return digits;
}
// Otherwise, return the original key for manual review
return key;
};
const pixKey = pixSettings.key_type === 'PHONE' ? normalizePhoneKey(pixSettings.key) : pixSettings.key;
const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`;

Comment on lines +2154 to +2165
const send = await this.createMessage(
instance,
getConversation,
content,
messageType,
false,
[],
body,
'WAID:' + body.key.id,
quotedMsg,
);
if (!send) this.logger.warn('message not sent');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): The return value of createMessage is checked only for falsy values.

If createMessage throws an error, it will bypass the warning. Wrap the call in try/catch to ensure errors are properly handled.

Suggested change
const send = await this.createMessage(
instance,
getConversation,
content,
messageType,
false,
[],
body,
'WAID:' + body.key.id,
quotedMsg,
);
if (!send) this.logger.warn('message not sent');
let send;
try {
send = await this.createMessage(
instance,
getConversation,
content,
messageType,
false,
[],
body,
'WAID:' + body.key.id,
quotedMsg,
);
if (!send) this.logger.warn('message not sent');
} catch (error) {
this.logger.warn('message not sent due to error', error);
}

@DavidsonGomes DavidsonGomes changed the base branch from main to develop November 13, 2025 17:20
@DavidsonGomes
Copy link
Collaborator

Fix the lint please, use npm run lint

@DavidsonGomes DavidsonGomes merged commit 7743063 into EvolutionAPI:develop Nov 19, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants