-
Notifications
You must be signed in to change notification settings - Fork 5.2k
feature: handle with interactive button message for pix #2220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: handle with interactive button message for pix #2220
Conversation
Reviewer's GuideThis 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 paymentsequenceDiagram
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
Class diagram for updated ChatwootService methodsclassDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this 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>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') { |
There was a problem hiding this comment.
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].
| const pixKey = pixSettings.key_type === 'PHONE' ? pixSettings.key.replace('+55', '') : pixSettings.key; | ||
| const content = `*${pixSettings.merchant_name}*\nChave PIX: ${pixKey} (${pixKeyType})`; |
There was a problem hiding this comment.
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.
| 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})`; |
| const send = await this.createMessage( | ||
| instance, | ||
| getConversation, | ||
| content, | ||
| messageType, | ||
| false, | ||
| [], | ||
| body, | ||
| 'WAID:' + body.key.id, | ||
| quotedMsg, | ||
| ); | ||
| if (!send) this.logger.warn('message not sent'); |
There was a problem hiding this comment.
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.
| 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); | |
| } |
|
Fix the lint please, use |
π Description
handle with interactive button message for pix
π Related Issue
π§ͺ Type of Change
π§ͺ Testing
πΈ Screenshots (if applicable)
β Checklist
π 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:
Enhancements: