diff --git a/flows/actions/testdata/transfer_airtime.json b/flows/actions/testdata/transfer_airtime.json index 1a065712e..6f7d1b16d 100644 --- a/flows/actions/testdata/transfer_airtime.json +++ b/flows/actions/testdata/transfer_airtime.json @@ -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", diff --git a/flows/actions/transfer_airtime.go b/flows/actions/transfer_airtime.go index d6e21ce6f..79df5a195 100644 --- a/flows/actions/transfer_airtime.go +++ b/flows/actions/transfer_airtime.go @@ -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()) @@ -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)) } diff --git a/flows/urn.go b/flows/urn.go index 7fc815ca2..5253394ba 100644 --- a/flows/urn.go +++ b/flows/urn.go @@ -3,6 +3,7 @@ package flows import ( "fmt" "net/url" + "slices" "github.com/go-playground/validator/v10" "github.com/nyaruka/gocommon/urns" @@ -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) } } diff --git a/services/airtime/dtone/service.go b/services/airtime/dtone/service.go index cfc3ea5e9..da0932c6d 100644 --- a/services/airtime/dtone/service.go +++ b/services/airtime/dtone/service.go @@ -3,6 +3,7 @@ package dtone import ( "fmt" "net/http" + "strings" "github.com/nyaruka/gocommon/httpx" "github.com/nyaruka/gocommon/stringsx" @@ -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)) } @@ -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 @@ -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)) }