Skip to content

Commit 1c064b6

Browse files
committed
driver: implement trips from the new API
Updates #49 Implements method - DriverTrips which correlates with https://developer.uber.com/docs/drivers/references/api/v1/partners-trips-get and allows one to query for driver trips within a period or paginate within them. * Also refactored to reuse DriverPayments which only varies from DriverTrips by populating Payments instead of Trips; the rest of the pagination and usage is the same Sample usage ```go package main import ( "fmt" "log" "os" "time" "github.com/orijtech/uber/v1" ) func main() { client, err := uber.NewClientFromOAuth2File(os.ExpandEnv("$HOME/.uber/credentials.json")) if err != nil { log.Fatal(err) } aWeekAgo := time.Now().Add(-1 * time.Hour * 7 * 24) yesterday := time.Now().Add(-1 * time.Hour * 24) trips, err := client.ListDriverTrips(&uber.DriverInfoQuery{ StartDate: &aWeekAgo, EndDate: &yesterday, MaxPageNumber: 2, Offset: 4, }) if err != nil { log.Fatal(err) } for page := range trips.Pages { if page.Err != nil { fmt.Printf("%d err: %v\n", page.PageNumber, page.Err) continue } for i, trip := range page.Trips { fmt.Printf("\t%d:: DriverID: %q\nFare: %.2f\n%#v\n", i, trip.DriverID, trip.Fare, trip) } fmt.Println() } } ```
1 parent 80c9009 commit 1c064b6

10 files changed

+671
-75
lines changed

example_test.go

+29-1
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ func Example_client_ListDriverPayments() {
518518
}
519519
aWeekAgo := time.Now().Add(-1 * time.Hour * 7 * 24)
520520
yesterday := time.Now().Add(-1 * time.Hour * 24)
521-
payments, err := client.ListDriverPayments(&uber.DriverPaymentsQuery{
521+
payments, err := client.ListDriverPayments(&uber.DriverInfoQuery{
522522
StartDate: &aWeekAgo,
523523
EndDate: &yesterday,
524524
})
@@ -536,3 +536,31 @@ func Example_client_ListDriverPayments() {
536536
fmt.Println()
537537
}
538538
}
539+
540+
func Example_client_ListDriverTrips() {
541+
client, err := uber.NewClientFromOAuth2File(os.ExpandEnv("$HOME/.uber/credentials.json"))
542+
if err != nil {
543+
log.Fatal(err)
544+
}
545+
aWeekAgo := time.Now().Add(-1 * time.Hour * 7 * 24)
546+
yesterday := time.Now().Add(-1 * time.Hour * 24)
547+
trips, err := client.ListDriverTrips(&uber.DriverInfoQuery{
548+
StartDate: &aWeekAgo,
549+
EndDate: &yesterday,
550+
MaxPageNumber: 2,
551+
Offset: 4,
552+
})
553+
if err != nil {
554+
log.Fatal(err)
555+
}
556+
for page := range trips.Pages {
557+
if page.Err != nil {
558+
fmt.Printf("%d err: %v\n", page.PageNumber, page.Err)
559+
continue
560+
}
561+
for i, trip := range page.Trips {
562+
fmt.Printf("\t%d:: DriverID: %q\nFare: %.2f\n%#v\n", i, trip.DriverID, trip.Fare, trip)
563+
}
564+
fmt.Println()
565+
}
566+
}

v1/deliveries.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,22 @@ type Item struct {
5959
}
6060

6161
type Endpoint struct {
62-
Location *Location `json:"location"`
62+
Location *Location `json:"location,omitempty"`
6363
Contact *Contact `json:"contact,omitempty"`
6464

6565
// Special instructions for the endpoint. This field
6666
// is optional and it is limited to 256 characters.
6767
SpecialInstructions otils.NullableString `json:"special_instructions,omitempty"`
6868

69-
SignatureRequired bool `json:"signature_required"`
69+
SignatureRequired bool `json:"signature_required,omitempty"`
7070

7171
// Indicates if the delivery includes alcohol. This
7272
// feature is only available to whitelisted businesses.
73-
IncludesAlcohol bool `json:"includes_alcohol"`
73+
IncludesAlcohol bool `json:"includes_alcohol,omitempty"`
7474

75-
ETAMinutes int `json:"eta"`
75+
ETAMinutes int `json:"eta,omitempty"`
76+
77+
TimestampUnix int64 `json:"timestamp,omitempty"`
7678
}
7779

7880
type Contact struct {

v1/driver.go

+81-67
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,70 @@ const (
5454
defaultThrottleDuration = 150 * time.Millisecond
5555
)
5656

57+
type DriverInfoResponse struct {
58+
Cancel func()
59+
Pages <-chan *DriverInfoPage
60+
}
61+
62+
type driverInfoWrap struct {
63+
Count int `json:"count"`
64+
Limit int `json:"limit"`
65+
Offset int `json:"offset"`
66+
Payments []*Payment `json:"payments"`
67+
Trips []*Trip `json:"trips"`
68+
}
69+
70+
func (dpq *DriverInfoQuery) toRealDriverQuery() *realDriverQuery {
71+
rdpq := &realDriverQuery{
72+
Offset: dpq.Offset,
73+
}
74+
if dpq.StartDate != nil {
75+
rdpq.StartTimeUnix = dpq.StartDate.Unix()
76+
}
77+
if dpq.EndDate != nil {
78+
rdpq.EndTimeUnix = dpq.EndDate.Unix()
79+
}
80+
return rdpq
81+
}
82+
83+
// realDriverQuery because it is the 1-to-1 match
84+
// with the fields sent it to query for the payments.
85+
// DriverQuery is just there for convenience and
86+
// easy API usage from callers e.g passing in a date without
87+
// having to worry about its exact Unix timestamp.
88+
type realDriverQuery struct {
89+
Offset int `json:"offset,omitempty"`
90+
LimitPerPage int `json:"limit,omitempty"`
91+
StartTimeUnix int64 `json:"from_time,omitempty"`
92+
EndTimeUnix int64 `json:"to_time,omitempty"`
93+
}
94+
95+
type DriverInfoQuery struct {
96+
Offset int `json:"offset,omitempty"`
97+
98+
// LimitPerPage is the number of items to retrieve per page.
99+
// Default is 5, maximum is 50.
100+
LimitPerPage int `json:"limit,omitempty"`
101+
102+
StartDate *time.Time `json:"start_date,omitempty"`
103+
EndDate *time.Time `json:"end_date,omitempty"`
104+
105+
MaxPageNumber int `json:"max_page_number,omitempty"`
106+
107+
Throttle time.Duration `json:"throttle,omitempty"`
108+
}
109+
110+
type DriverInfoPage struct {
111+
PageNumber int `json:"page_number,omitempty"`
112+
Payments []*Payment `json:"payments,omitempty"`
113+
Trips []*Trip `json:"trips,omitempty"`
114+
Err error `json:"error"`
115+
}
116+
117+
func (c *Client) ListDriverTrips(dpq *DriverInfoQuery) (*DriverInfoResponse, error) {
118+
return c.listDriverInfo(dpq, "/partners/trips")
119+
}
120+
57121
// DriverPayments returns the payments for the given driver.
58122
// Payments are available at this endpoint in near real-time. Some entries,
59123
// such as "device_subscription" will appear on a periodic basis when actually
@@ -63,9 +127,13 @@ const (
63127
// there will be no payments associated and the response will always be an empty
64128
// array. Drivers working for fleet managers will receive payments from the fleet
65129
// manager and not from Uber.
66-
func (c *Client) ListDriverPayments(dpq *DriverPaymentsQuery) (*DriverPaymentsResponse, error) {
130+
func (c *Client) ListDriverPayments(dpq *DriverInfoQuery) (*DriverInfoResponse, error) {
131+
return c.listDriverInfo(dpq, "/partners/payments")
132+
}
133+
134+
func (c *Client) listDriverInfo(dpq *DriverInfoQuery, path string) (*DriverInfoResponse, error) {
67135
if dpq == nil {
68-
dpq = new(DriverPaymentsQuery)
136+
dpq = new(DriverInfoQuery)
69137
}
70138

71139
throttleDuration := dpq.Throttle
@@ -80,22 +148,22 @@ func (c *Client) ListDriverPayments(dpq *DriverPaymentsQuery) (*DriverPaymentsRe
80148
return maxPageNumber > 0 && pageNumber >= maxPageNumber
81149
}
82150

83-
baseURL := fmt.Sprintf("%s/partners/payments", c.baseURL(driverV1API))
84-
rdpq := dpq.toRealDriverPaymentsQuery()
151+
baseURL := fmt.Sprintf("%s%s", c.baseURL(driverV1API), path)
152+
rdpq := dpq.toRealDriverQuery()
85153
limitPerPage := rdpq.LimitPerPage
86154
if limitPerPage <= 0 {
87155
limitPerPage = defaultDriverPaymentsLimitPerPage
88156
}
89157

90158
cancelChan, cancelFn := makeCancelParadigm()
91-
resChan := make(chan *DriverPaymentsPage)
159+
resChan := make(chan *DriverInfoPage)
92160
go func() {
93161
defer close(resChan)
94162

95163
pageNumber := 0
96164

97165
for {
98-
curPage := new(DriverPaymentsPage)
166+
curPage := new(DriverInfoPage)
99167
curPage.PageNumber = pageNumber
100168

101169
qv, err := otils.ToURLValues(rdpq)
@@ -123,17 +191,21 @@ func (c *Client) ListDriverPayments(dpq *DriverPaymentsQuery) (*DriverPaymentsRe
123191
return
124192
}
125193

126-
recv := new(driverPaymentsWrap)
194+
recv := new(driverInfoWrap)
127195
if err := json.Unmarshal(blob, recv); err != nil {
128196
curPage.Err = err
129197
resChan <- curPage
130198
return
131199
}
132-
if len(recv.Payments) == 0 { // No payments sent back, so sign that we are at the end
200+
201+
// No payments nor trips sent back, so a sign that we are at the end
202+
if len(recv.Payments) == 0 && len(recv.Trips) == 0 {
133203
return
134204
}
135205

206+
curPage.Trips = recv.Trips
136207
curPage.Payments = recv.Payments
208+
137209
resChan <- curPage
138210

139211
pageNumber += 1
@@ -151,68 +223,10 @@ func (c *Client) ListDriverPayments(dpq *DriverPaymentsQuery) (*DriverPaymentsRe
151223
}
152224
}()
153225

154-
resp := &DriverPaymentsResponse{
226+
resp := &DriverInfoResponse{
155227
Cancel: cancelFn,
156228
Pages: resChan,
157229
}
158230

159231
return resp, nil
160232
}
161-
162-
type DriverPaymentsResponse struct {
163-
Cancel func()
164-
Pages <-chan *DriverPaymentsPage
165-
}
166-
167-
type driverPaymentsWrap struct {
168-
Count int `json:"count"`
169-
Limit int `json:"limit"`
170-
Offset int `json:"offset"`
171-
Payments []*Payment `json:"payments"`
172-
}
173-
174-
func (dpq *DriverPaymentsQuery) toRealDriverPaymentsQuery() *realDriverPaymentsQuery {
175-
rdpq := &realDriverPaymentsQuery{
176-
Offset: dpq.Offset,
177-
}
178-
if dpq.StartDate != nil {
179-
rdpq.StartTimeUnix = dpq.StartDate.Unix()
180-
}
181-
if dpq.EndDate != nil {
182-
rdpq.EndTimeUnix = dpq.EndDate.Unix()
183-
}
184-
return rdpq
185-
}
186-
187-
// realDriverPaymentsQuery because it is the 1-to-1 match
188-
// with the fields sent it to query for the payments.
189-
// DriverPaymentsQuery is just there for convenience and
190-
// easy API usage from callers e.g passing in a date without
191-
// having to worry about its exact Unix timestamp.
192-
type realDriverPaymentsQuery struct {
193-
Offset int `json:"offset,omitempty"`
194-
LimitPerPage int `json:"limit,omitempty"`
195-
StartTimeUnix int64 `json:"from_time,omitempty"`
196-
EndTimeUnix int64 `json:"to_time,omitempty"`
197-
}
198-
199-
type DriverPaymentsQuery struct {
200-
Offset int `json:"offset,omitempty"`
201-
202-
// LimitPerPage is the number of items to retrieve per page.
203-
// Default is 5, maximum is 50.
204-
LimitPerPage int `json:"limit,omitempty"`
205-
206-
StartDate *time.Time `json:"start_date,omitempty"`
207-
EndDate *time.Time `json:"end_date,omitempty"`
208-
209-
MaxPageNumber int `json:"max_page_number,omitempty"`
210-
211-
Throttle time.Duration `json:"throttle,omitempty"`
212-
}
213-
214-
type DriverPaymentsPage struct {
215-
PageNumber int `json:"page_number,omitempty"`
216-
Payments []*Payment `json:"payments,omitempty"`
217-
Err error `json:"error"`
218-
}

v1/history.go

+19
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,30 @@ type Trip struct {
4242

4343
ProductID string `json:"product_id,omitempty"`
4444
RequestID string `json:"request_id,omitempty"`
45+
TripID string `json:"trip_id,omitempty"`
46+
DriverID string `json:"driver_id,omitempty"`
4547

4648
Unit string `json:"distance_unit,omitempty"`
4749

50+
Duration otils.NullableFloat64 `json:"duration,omitempty"`
4851
DurationEstimate otils.NullableFloat64 `json:"duration_estimate,omitempty"`
52+
53+
Distance otils.NullableFloat64 `json:"distance,omitempty"`
4954
DistanceEstimate otils.NullableFloat64 `json:"distance_estimate,omitempty"`
55+
56+
VehicleID otils.NullableString `json:"vehicle_id,omitempty"`
57+
58+
SurgeMultiplier otils.NullableFloat64 `json:"surge_multiplier,omitempty"`
59+
Fare otils.NullableFloat64 `json:"fare,omitempty"`
60+
Dropoff *Endpoint `json:"dropoff,omitempty"`
61+
Pickup *Endpoint `json:"pickup,omitempty"`
62+
StatusChanges []*StatusChange `json:"status_changes,omitempty"`
63+
CurrencyCode CurrencyCode `json:"currency_code,omitempty"`
64+
}
65+
66+
type StatusChange struct {
67+
Status Status `json:"status,omitempty"`
68+
TimestampUnix int64 `json:"timestamp,omitempty"`
5069
}
5170

5271
type Place struct {

v1/testdata/driver_trips_0.json

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{
2+
"count": 1200,
3+
"limit": 2,
4+
"trips": [
5+
{
6+
"fare": 6.2,
7+
"dropoff": {
8+
"timestamp": 1502844378
9+
},
10+
"vehicle_id": "0082b54a-6a5e-4f6b-b999-b0649f286381",
11+
"distance": 0.37,
12+
"start_city": {
13+
"latitude": 38.3498,
14+
"display_name": "Charleston, WV",
15+
"longitude": -81.6326
16+
},
17+
"status_changes": [
18+
{
19+
"status": "accepted",
20+
"timestamp": 1502843899
21+
},
22+
{
23+
"status": "driver_arrived",
24+
"timestamp": 1502843900
25+
},
26+
{
27+
"status": "trip_began",
28+
"timestamp": 1502843903
29+
},
30+
{
31+
"status": "completed",
32+
"timestamp": 1502844378
33+
}
34+
],
35+
"surge_multiplier": 1,
36+
"pickup": {
37+
"timestamp": 1502843903
38+
},
39+
"driver_id": "8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==",
40+
"status": "completed",
41+
"duration": 475,
42+
"trip_id": "b5613b6a-fe74-4704-a637-50f8d51a8bb1",
43+
"currency_code": "USD"
44+
},
45+
{
46+
"fare": 8.2,
47+
"dropoff": {
48+
"timestamp": 1502846443
49+
},
50+
"vehicle_id": "f227de83-0f6a-4422-a733-1e8b781b6ff7",
51+
"distance": 2.11,
52+
"start_city": {
53+
"latitude": 38.3498,
54+
"display_name": "Charleston, WV",
55+
"longitude": -81.6326
56+
},
57+
"status_changes": [
58+
{
59+
"status": "accepted",
60+
"timestamp": 1502844744
61+
},
62+
{
63+
"status": "driver_arrived",
64+
"timestamp": 1502843900
65+
},
66+
{
67+
"status": "trip_began",
68+
"timestamp": 1502843903
69+
},
70+
{
71+
"status": "completed",
72+
"timestamp": 1502844378
73+
}
74+
],
75+
"surge_multiplier": 1.93,
76+
"pickup": {
77+
"timestamp": 1502843903
78+
},
79+
"driver_id": "8LvWuRAq2511gmr8EMkovekFNa2848lyMaQevIto-aXmnK9oKNRtfTxYLgPq9OSt8EzAu5pDB7XiaQIrcp-zXgOA5EyK4h00U6D1o7aZpXIQah--U77Eh7LEBiksj2rahB==",
80+
"status": "completed",
81+
"duration": 475,
82+
"trip_id": "b5613b6a-fe74-4704-a637-50f8d51a8bb1",
83+
"currency_code": "USD"
84+
}
85+
],
86+
"offset": 0
87+
}

v1/testdata/driver_trips_10.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

0 commit comments

Comments
 (0)