Skip to content

Commit

Permalink
Merge pull request #152 from weni-ai/update-staging
Browse files Browse the repository at this point in the history
Update staging
  • Loading branch information
paulobernardoaf authored Nov 27, 2024
2 parents c44fcd2 + 9d2ab9a commit 8a276de
Show file tree
Hide file tree
Showing 16 changed files with 580 additions and 397 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CI
on: [push, pull_request]
env:
go-version: '1.17.x'
go-version: '1.23.x'
redis-version: '3.2.4'
jobs:
test:
Expand Down
16 changes: 16 additions & 0 deletions WENI-CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
1.18.5
----------
* Fix: document name on template message for whatsapp cloud

1.18.4
----------
* Fix: Handle error for Whatsapp messages without text but with quick replies and attachments

1.18.3
----------
* Hotfix: MsgParts index out of range

1.18.2
----------
* Feat: configuration for billing queue name on env var

1.18.1
----------
* Fix: document name when message have quick replies on whatsapp handler
Expand Down
203 changes: 121 additions & 82 deletions backends/rapidpro/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,104 +920,143 @@ func (m *DBMsg) OrderDetailsMessage() *courier.OrderDetailsMessage {
return nil
}

if interactionType, ok := metadata["interaction_type"].(string); ok && interactionType == "order_details" {
if orderDetailsMessageData, ok := metadata["order_details_message"].(map[string]interface{}); ok {
orderDetailsMessage := &courier.OrderDetailsMessage{}
if referenceID, ok := orderDetailsMessageData["reference_id"].(string); ok {
orderDetailsMessage.ReferenceID = referenceID
if orderDetailsMessageData, ok := metadata["order_details_message"].(map[string]interface{}); ok {
orderDetailsMessage := &courier.OrderDetailsMessage{}
if referenceID, ok := orderDetailsMessageData["reference_id"].(string); ok {
orderDetailsMessage.ReferenceID = referenceID
}
if paymentSettings, ok := orderDetailsMessageData["payment_settings"].(map[string]interface{}); ok {
orderDetailsMessage.PaymentSettings = courier.OrderPaymentSettings{}
if payment_type, ok := paymentSettings["type"].(string); ok {
orderDetailsMessage.PaymentSettings.Type = payment_type
}
if payment_link, ok := paymentSettings["payment_link"].(string); ok {
orderDetailsMessage.PaymentSettings.PaymentLink = payment_link
}
if paymentSettings, ok := orderDetailsMessageData["payment_settings"].(map[string]interface{}); ok {
orderDetailsMessage.PaymentSettings = courier.OrderPaymentSettings{}
if payment_type, ok := paymentSettings["type"].(string); ok {
orderDetailsMessage.PaymentSettings.Type = payment_type
if pix_config, ok := paymentSettings["pix_config"].(map[string]interface{}); ok {
orderDetailsMessage.PaymentSettings.PixConfig = courier.OrderPixConfig{}
if pix_config_key, ok := pix_config["key"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.Key = pix_config_key
}
if payment_link, ok := paymentSettings["payment_link"].(string); ok {
orderDetailsMessage.PaymentSettings.PaymentLink = payment_link
if pix_config_key_type, ok := pix_config["key_type"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.KeyType = pix_config_key_type
}
if pix_config, ok := paymentSettings["pix_config"].(map[string]interface{}); ok {
orderDetailsMessage.PaymentSettings.PixConfig = courier.OrderPixConfig{}
if pix_config_key, ok := pix_config["key"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.Key = pix_config_key
}
if pix_config_key_type, ok := pix_config["key_type"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.KeyType = pix_config_key_type
}
if pix_config_merchant_name, ok := pix_config["merchant_name"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.MerchantName = pix_config_merchant_name
}
if pix_config_code, ok := pix_config["code"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.Code = pix_config_code
}
if pix_config_merchant_name, ok := pix_config["merchant_name"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.MerchantName = pix_config_merchant_name
}
if pix_config_code, ok := pix_config["code"].(string); ok {
orderDetailsMessage.PaymentSettings.PixConfig.Code = pix_config_code
}
}
if totalAmount, ok := orderDetailsMessageData["total_amount"].(float64); ok {
orderDetailsMessage.TotalAmount = int(totalAmount)
}
if orderData, ok := orderDetailsMessageData["order"].(map[string]interface{}); ok {
orderDetailsMessage.Order = courier.Order{}
if itemsData, ok := orderData["items"].([]interface{}); ok {
orderDetailsMessage.Order.Items = make([]courier.OrderItem, len(itemsData))
for i, item := range itemsData {
if itemMap, ok := item.(map[string]interface{}); ok {
itemAmount := itemMap["amount"].(map[string]interface{})
item := courier.OrderItem{
RetailerID: itemMap["retailer_id"].(string),
Name: itemMap["name"].(string),
Quantity: int(itemMap["quantity"].(float64)),
Amount: courier.OrderAmountWithOffset{
Value: int(itemAmount["value"].(float64)),
Offset: int(itemAmount["offset"].(float64)),
},
}
}
if totalAmount, ok := orderDetailsMessageData["total_amount"].(float64); ok {
orderDetailsMessage.TotalAmount = int(totalAmount)
}
if orderData, ok := orderDetailsMessageData["order"].(map[string]interface{}); ok {
orderDetailsMessage.Order = courier.Order{}
if itemsData, ok := orderData["items"].([]interface{}); ok {
orderDetailsMessage.Order.Items = make([]courier.OrderItem, len(itemsData))
for i, item := range itemsData {
if itemMap, ok := item.(map[string]interface{}); ok {
itemAmount := itemMap["amount"].(map[string]interface{})
item := courier.OrderItem{
RetailerID: itemMap["retailer_id"].(string),
Name: itemMap["name"].(string),
Quantity: int(itemMap["quantity"].(float64)),
Amount: courier.OrderAmountWithOffset{
Value: int(itemAmount["value"].(float64)),
Offset: int(itemAmount["offset"].(float64)),
},
}

if itemMap["sale_amount"] != nil {
saleAmount := itemMap["sale_amount"].(map[string]interface{})
item.SaleAmount = &courier.OrderAmountWithOffset{
Value: int(saleAmount["value"].(float64)),
Offset: int(saleAmount["offset"].(float64)),
}
if itemMap["sale_amount"] != nil {
saleAmount := itemMap["sale_amount"].(map[string]interface{})
item.SaleAmount = &courier.OrderAmountWithOffset{
Value: int(saleAmount["value"].(float64)),
Offset: int(saleAmount["offset"].(float64)),
}

orderDetailsMessage.Order.Items[i] = item
}

orderDetailsMessage.Order.Items[i] = item
}
}
if subtotal, ok := orderData["subtotal"].(float64); ok {
orderDetailsMessage.Order.Subtotal = int(subtotal)
}
if subtotal, ok := orderData["subtotal"].(float64); ok {
orderDetailsMessage.Order.Subtotal = int(subtotal)
}
if taxData, ok := orderData["tax"].(map[string]interface{}); ok {
orderDetailsMessage.Order.Tax = courier.OrderAmountWithDescription{}
if value, ok := taxData["value"].(float64); ok {
orderDetailsMessage.Order.Tax.Value = int(value)
}
if taxData, ok := orderData["tax"].(map[string]interface{}); ok {
orderDetailsMessage.Order.Tax = courier.OrderAmountWithDescription{}
if value, ok := taxData["value"].(float64); ok {
orderDetailsMessage.Order.Tax.Value = int(value)
}
if description, ok := taxData["description"].(string); ok {
orderDetailsMessage.Order.Tax.Description = description
}
if description, ok := taxData["description"].(string); ok {
orderDetailsMessage.Order.Tax.Description = description
}
if shippingData, ok := orderData["shipping"].(map[string]interface{}); ok {
orderDetailsMessage.Order.Shipping = courier.OrderAmountWithDescription{}
if value, ok := shippingData["value"].(float64); ok {
orderDetailsMessage.Order.Shipping.Value = int(value)
}
if description, ok := shippingData["description"].(string); ok {
orderDetailsMessage.Order.Shipping.Description = description
}
}
if shippingData, ok := orderData["shipping"].(map[string]interface{}); ok {
orderDetailsMessage.Order.Shipping = courier.OrderAmountWithDescription{}
if value, ok := shippingData["value"].(float64); ok {
orderDetailsMessage.Order.Shipping.Value = int(value)
}
if discountData, ok := orderData["discount"].(map[string]interface{}); ok {
orderDetailsMessage.Order.Discount = courier.OrderDiscount{}
if value, ok := discountData["value"].(float64); ok {
orderDetailsMessage.Order.Discount.Value = int(value)
}
if description, ok := discountData["description"].(string); ok {
orderDetailsMessage.Order.Discount.Description = description
}
if programName, ok := discountData["program_name"].(string); ok {
orderDetailsMessage.Order.Discount.ProgramName = programName
}
if description, ok := shippingData["description"].(string); ok {
orderDetailsMessage.Order.Shipping.Description = description
}
}
if discountData, ok := orderData["discount"].(map[string]interface{}); ok {
orderDetailsMessage.Order.Discount = courier.OrderDiscount{}
if value, ok := discountData["value"].(float64); ok {
orderDetailsMessage.Order.Discount.Value = int(value)
}
if description, ok := discountData["description"].(string); ok {
orderDetailsMessage.Order.Discount.Description = description
}
if programName, ok := discountData["program_name"].(string); ok {
orderDetailsMessage.Order.Discount.ProgramName = programName
}
}
}
return orderDetailsMessage
}

return nil
}

func (m *DBMsg) Buttons() []courier.ButtonComponent {
if m.Metadata_ == nil {
return nil
}

var metadata map[string]interface{}
err := json.Unmarshal(m.Metadata_, &metadata)
if err != nil {
return nil
}

if metadata == nil {
return nil
}

if buttonsData, ok := metadata["buttons"].([]interface{}); ok {
buttons := make([]courier.ButtonComponent, len(buttonsData))
for i, button := range buttonsData {
buttonMap := button.(map[string]interface{})
buttons[i] = courier.ButtonComponent{
SubType: buttonMap["sub_type"].(string),
Parameters: []courier.ButtonParam{},
}

if buttonMap["parameters"] != nil {
parameters := buttonMap["parameters"].([]interface{})
for _, parameter := range parameters {
parameterMap := parameter.(map[string]interface{})
buttons[i].Parameters = append(buttons[i].Parameters, courier.ButtonParam{
Type: parameterMap["type"].(string),
Text: parameterMap["text"].(string),
})
}
}
return orderDetailsMessage
}
return buttons
}

return nil
Expand Down
10 changes: 5 additions & 5 deletions billing/billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"github.com/sirupsen/logrus"
)

const QUEUE_NAME = "billing-backup"

// Message represents a object that is sent to the billing service
//
// {
Expand Down Expand Up @@ -61,10 +59,11 @@ type Client interface {
type rabbitmqRetryClient struct {
publisher rabbitroutine.Publisher
conn *rabbitroutine.Connector
queueName string
}

// NewRMQBillingResilientClient creates a new billing service client implementation using RabbitMQ with publish retry and reconnect features
func NewRMQBillingResilientClient(url string, retryAttempts int, retryDelay int) (Client, error) {
func NewRMQBillingResilientClient(url string, retryAttempts int, retryDelay int, queueName string) (Client, error) {
cconn, err := amqp.Dial(url)
if err != nil {
return nil, err
Expand All @@ -77,7 +76,7 @@ func NewRMQBillingResilientClient(url string, retryAttempts int, retryDelay int)
}
defer ch.Close()
_, err = ch.QueueDeclare(
QUEUE_NAME,
queueName,
false,
false,
false,
Expand Down Expand Up @@ -126,6 +125,7 @@ func NewRMQBillingResilientClient(url string, retryAttempts int, retryDelay int)
return &rabbitmqRetryClient{
publisher: pub,
conn: conn,
queueName: queueName,
}, nil
}

Expand All @@ -135,7 +135,7 @@ func (c *rabbitmqRetryClient) Send(msg Message) error {
err := c.publisher.Publish(
ctx,
"",
QUEUE_NAME,
c.queueName,
amqp.Publishing{
ContentType: "application/json",
Body: msgMarshalled,
Expand Down
22 changes: 12 additions & 10 deletions billing/billing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/stretchr/testify/assert"
)

const billingTestQueueName = "testqueue"

func TestInitialization(t *testing.T) {
connURL := "amqp://localhost:5672/"
conn, err := amqp.Dial(connURL)
Expand All @@ -25,7 +27,7 @@ func TestInitialization(t *testing.T) {
}
defer conn.Close()
defer ch.Close()
defer ch.QueueDelete(QUEUE_NAME, false, false, false)
defer ch.QueueDelete(billingTestQueueName, false, false, false)
}

func TestBillingResilientClient(t *testing.T) {
Expand All @@ -37,7 +39,7 @@ func TestBillingResilientClient(t *testing.T) {
t.Fatal(errors.Wrap(err, "failed to declare a channel for consumer"))
}
defer ch.Close()
defer ch.QueueDelete(QUEUE_NAME, false, false, false)
defer ch.QueueDelete(billingTestQueueName, false, false, false)

msgUUID, _ := uuid.NewV4()
msg := NewMessage(
Expand All @@ -53,14 +55,14 @@ func TestBillingResilientClient(t *testing.T) {
nil,
)

billingClient, err := NewRMQBillingResilientClient(connURL, 3, 1000)
billingClient, err := NewRMQBillingResilientClient(connURL, 3, 1000, billingTestQueueName)
time.Sleep(1 * time.Second)
assert.NoError(t, err)
err = billingClient.Send(msg)
assert.NoError(t, err)

msgs, err := ch.Consume(
QUEUE_NAME,
billingTestQueueName,
"",
true,
false,
Expand Down Expand Up @@ -101,7 +103,7 @@ func TestBillingResilientClientSendAsync(t *testing.T) {
t.Fatal(errors.Wrap(err, "failed to declare a channel for consumer"))
}
defer ch.Close()
defer ch.QueueDelete(QUEUE_NAME, false, false, false)
defer ch.QueueDelete(billingTestQueueName, false, false, false)

msgUUID, _ := uuid.NewV4()
msg := NewMessage(
Expand All @@ -117,14 +119,14 @@ func TestBillingResilientClientSendAsync(t *testing.T) {
nil,
)

billingClient, err := NewRMQBillingResilientClient(connURL, 3, 1000)
billingClient, err := NewRMQBillingResilientClient(connURL, 3, 1000, billingTestQueueName)
time.Sleep(1 * time.Second)
assert.NoError(t, err)
billingClient.SendAsync(msg, nil, nil)

assert.NoError(t, err)
msgs, err := ch.Consume(
QUEUE_NAME,
billingTestQueueName,
"",
true,
false,
Expand Down Expand Up @@ -165,7 +167,7 @@ func TestBillingResilientClientSendAsyncWithPanic(t *testing.T) {
t.Fatal(errors.Wrap(err, "failed to declare a channel for consumer"))
}
defer ch.Close()
defer ch.QueueDelete(QUEUE_NAME, false, false, false)
defer ch.QueueDelete(billingTestQueueName, false, false, false)

msgUUID, _ := uuid.NewV4()
msg := NewMessage(
Expand All @@ -181,15 +183,15 @@ func TestBillingResilientClientSendAsyncWithPanic(t *testing.T) {
nil,
)

billingClient, err := NewRMQBillingResilientClient(connURL, 3, 1000)
billingClient, err := NewRMQBillingResilientClient(connURL, 3, 1000, billingTestQueueName)
time.Sleep(1 * time.Second)
assert.NoError(t, err)
time.Sleep(1 * time.Second)
billingClient.SendAsync(msg, nil, func() { panic("test panic") })

assert.NoError(t, err)
msgs, err := ch.Consume(
QUEUE_NAME,
billingTestQueueName,
"",
false,
false,
Expand Down
Loading

0 comments on commit 8a276de

Please sign in to comment.