Skip to content

Commit

Permalink
Merge pull request #1267 from nyaruka/WA-airtime
Browse files Browse the repository at this point in the history
Support sending for WhatsApp URNs
  • Loading branch information
rowanseymour authored Jun 11, 2024
2 parents 8ef199a + a96fe24 commit 885ce83
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 12 deletions.
2 changes: 1 addition & 1 deletion flows/actions/testdata/transfer_airtime.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"type": "error",
"created_on": "2018-10-18T14:20:30.000123456Z",
"step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c",
"text": "can't transfer airtime to contact without a tel URN"
"text": "can't transfer airtime to contact without a phone number"
},
{
"type": "run_result_changed",
Expand Down
12 changes: 7 additions & 5 deletions flows/actions/transfer_airtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ func (a *TransferAirtimeAction) transfer(run flows.Run, logEvent flows.EventCall
contact := run.Contact()

// fail if the contact doesn't have a tel URN
telURNs := contact.URNs().WithScheme(urns.Phone.Prefix)
telURNs := contact.URNs().WithScheme(urns.Phone.Prefix, urns.WhatsApp.Prefix)
if len(telURNs) == 0 {
return nil, errors.New("can't transfer airtime to contact without a tel URN")
return nil, errors.New("can't transfer airtime to contact without a phone number")
}

recipient := telURNs[0].URN()

// if contact's preferred channel is a phone number, use that as the sender
var sender urns.URN
channel := contact.PreferredChannel()
if channel != nil && channel.SupportsScheme(urns.Phone.Prefix) {
sender, _ = urns.Parse("tel:" + channel.Address())
if channel != nil && channel.SupportsScheme(recipient.Scheme()) {
sender, _ = urns.Parse(recipient.Scheme() + ":" + channel.Address())
}

svc, err := run.Session().Engine().Services().Airtime(run.Session().Assets())
Expand All @@ -85,7 +87,7 @@ func (a *TransferAirtimeAction) transfer(run flows.Run, logEvent flows.EventCall

httpLogger := &flows.HTTPLogger{}

transfer, err := svc.Transfer(sender, telURNs[0].URN(), a.Amounts, httpLogger.Log)
transfer, err := svc.Transfer(sender, recipient, a.Amounts, httpLogger.Log)
if transfer != nil {
logEvent(events.NewAirtimeTransferred(transfer, httpLogger.Logs))
}
Expand Down
7 changes: 4 additions & 3 deletions flows/urn.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package flows
import (
"fmt"
"net/url"
"slices"

"github.com/go-playground/validator/v10"
"github.com/nyaruka/gocommon/urns"
Expand Down Expand Up @@ -173,11 +174,11 @@ func (l URNList) clone() URNList {
return urns
}

// WithScheme returns a new URN list containing of only URNs of the given scheme
func (l URNList) WithScheme(scheme string) URNList {
// WithScheme returns a new URN list containing of only URNs of the given schemes
func (l URNList) WithScheme(schemes ...string) URNList {
var matching URNList
for _, u := range l {
if u.urn.Scheme() == scheme {
if slices.Contains(schemes, u.urn.Scheme()) {
matching = append(matching, u)
}
}
Expand Down
11 changes: 8 additions & 3 deletions services/airtime/dtone/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dtone
import (
"fmt"
"net/http"
"strings"

"github.com/nyaruka/gocommon/httpx"
"github.com/nyaruka/gocommon/stringsx"
Expand Down Expand Up @@ -34,8 +35,12 @@ func (s *service) Transfer(sender urns.URN, recipient urns.URN, amounts map[stri
DesiredAmount: decimal.Zero,
ActualAmount: decimal.Zero,
}
recipientPhoneNumber := recipient.Path()
if !strings.HasPrefix(recipientPhoneNumber, "+") {
recipientPhoneNumber = "+" + recipientPhoneNumber
}

operators, trace, err := s.client.LookupMobileNumber(recipient.Path())
operators, trace, err := s.client.LookupMobileNumber(recipientPhoneNumber)
if trace != nil {
logHTTP(flows.NewHTTPLog(trace, flows.HTTPStatusFromCode, s.redactor))
}
Expand All @@ -52,7 +57,7 @@ func (s *service) Transfer(sender urns.URN, recipient urns.URN, amounts map[stri
}
}
if operator == nil {
return transfer, fmt.Errorf("unable to find operator for number %s", recipient.Path())
return transfer, fmt.Errorf("unable to find operator for number %s", recipientPhoneNumber)
}

// fetch available products for this operator
Expand Down Expand Up @@ -94,7 +99,7 @@ func (s *service) Transfer(sender urns.URN, recipient urns.URN, amounts map[stri
transfer.DesiredAmount = amounts[transfer.Currency]

// request synchronous confirmed transaction for this product
tx, trace, err := s.client.TransactionAsync(string(transfer.UUID), product.ID, recipient.Path())
tx, trace, err := s.client.TransactionAsync(string(transfer.UUID), product.ID, recipientPhoneNumber)
if trace != nil {
logHTTP(flows.NewHTTPLog(trace, flows.HTTPStatusFromCode, s.redactor))
}
Expand Down

0 comments on commit 885ce83

Please sign in to comment.