-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathshipments.go
187 lines (173 loc) · 6.52 KB
/
shipments.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package postmaster
import (
"errors"
"fmt"
"strconv"
)
// Shipment is a base object used in Shipment API requests.
// Options will always be a nested map of strings, meaning that you need to type
// every nested interface as map[string]interface{} or map[string]string.
type Shipment struct {
p *Postmaster `json:"-"`
Id int `json:"id,omitempty"`
// These fields are filled by User
To *Address `json:"to,omitempty"`
From *Address `json:"from,omitempty"`
Package *Package `json:"package,omitempty"`
Packages []Package `json:"packages,omitempty"`
Carrier string `json:"carrier"`
Service string `json:"service"`
PONumber string `json:"po_number,omitempty"`
References []string `json:"references,omitempty"`
Options map[string]interface{} `json:"options,omitempty"`
Signature string `json:"signature,omitempty"`
Label *Label `json:"label,omitempty"`
// These fields are returned by server
Status string `json:"status,omitempty"`
Tracking []string `json:"tracking,omitempty"`
PackageCount int `json:"package_count,omitempty"`
CreatedAt int `json:"created_at,omitempty"`
Cost int `json:"cost,omitempty"`
Prepaid bool `json:"prepaid,omitempty"`
}
// ShipmentList is returned when asking for list of shipments.
type ShipmentList struct {
Results []Shipment `json:"results"`
Cursor string `json:"cursor,omitempty"`
PreviousCursor string `json:"previous_cursor,omitempty"`
}
// Package (not to be confused with packages in fitting API, which are called "Boxes")
// is being used in Shipment request.
type Package struct {
Id int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Width float32 `json:"width,omitempty"`
Height float32 `json:"height,omitempty"`
Length float32 `json:"length,omitempty"`
Weight float32 `json:"weight,omitempty"`
Customs *Custom `json:"customs,omitempty"`
DimensionUnits string `json:"dimension_units,omitempty"`
WeightUnits string `json:"weight_units,omitempty"`
Type string `json:"type,omitempty"`
LabelUrl string `json:"label_url,omitempty"`
}
// CustomContent is being used as a single item in Custom object.
type CustomContent struct {
Description string `json:"description,omitempty"`
Quantity int `json:"quantity,omitempty"`
Value string `json:"value,omitempty"`
Weight float32 `json:"weight,omitempty"`
WeightUnits string `json:"weight_units,omitempty"`
HSTariffNumber string `json:"hs_tariff_number,omitempty"`
CountryOfOrigin string `json:"country_of_origin,omitempty"`
}
// Custom is being used per Package. It is necessary only in international
// packages.
type Custom struct {
Type string `json:"type,omitempty"`
Comments string `json:"comments,omitempty"`
InvoiceNumber string `json:"invoice_number,omitempty"`
Contents []CustomContent `json:"contents,omitempty"`
}
// Label is used per Shipment
type Label struct {
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Size string `json:"size,omitempty"`
}
// Shipment creates a brand new Shipment structure. Don't use new(postmaster.Shipment),
// use this function instead.
func (p *Postmaster) Shipment() (s *Shipment) {
s = new(Shipment)
s.p = p
s.Id = -1 // default for "null" Shipment
return
}
// Create creates new Shipment in API.
// You musn't invoke this function from an existing Shipment (i.e. shipment.Id > -1).
func (s *Shipment) Create() (*Shipment, error) {
if s.Id != -1 {
return nil, errors.New("You can't create an existing shipment.")
}
_, err := post(s.p, "v1", "shipments", s, s)
return s, err
}
// Get fetches single Shipment from API, and replaces existing Shipment structure.
// You musn't invoke this function from an "empty" Shipment (i.e. shipment.Id == -1).
func (s *Shipment) Get() (*Shipment, error) {
if s.Id == -1 {
return nil, errors.New("You must provide a shipment ID.")
}
endpoint := fmt.Sprintf("shipments/%d", s.Id)
_, err := get(s.p, "v1", endpoint, nil, s)
return s, err
}
// Void sets Shipment's status to "voided".
// You musn't invoke this function from an "empty" Shipment (i.e. shipment.Id == -1).
func (s *Shipment) Void() (bool, error) {
if s.Id == -1 {
return false, errors.New("You must provide a shipment ID.")
}
endpoint := fmt.Sprintf("shipments/%d/void", s.Id)
var res map[string]string
_, err := del(s.p, "v1", endpoint, nil, &res)
if res["message"] == "OK" {
s.Status = "Voided"
}
return res["message"] == "OK", err
}
// Track returns TrackingResponse for Shipment.
// You musn't invoke this function from an "empty" Shipment (i.e. shipment.Id == -1).
// In order to track shipment just by its tracking number, use Postmaster.TrackRef()
// function.
func (s *Shipment) Track() (*TrackingResponse, error) {
if s.Id == -1 {
return nil, errors.New("You must provide a shipment ID.")
}
endpoint := fmt.Sprintf("shipments/%d/track", s.Id)
res := TrackingResponse{}
_, err := get(s.p, "v1", endpoint, nil, &res)
return &res, err
}
// ListShipments returns a list of shipments, with limit, status and cursor (e.g. for pagination).
func (p *Postmaster) ListShipments(limit int, cursor string, status string) (*ShipmentList, error) {
params := make(map[string]string)
if limit > 0 {
params["limit"] = strconv.Itoa(limit)
}
if cursor != "" {
params["cursor"] = cursor
}
if status != "" {
params["status"] = status
}
res := new(ShipmentList)
_, err := get(p, "v1", "shipments", params, &res)
// Set Postmaster "base" object for each shipment, so we can use API with them
for k, _ := range res.Results {
res.Results[k].p = p
}
return res, err
}
// FindShipments returns a list of shipments matching given search query, with limit,
// status and cursor (e.g. for pagination).
func (p *Postmaster) FindShipments(q string, limit int, cursor string) (*ShipmentList, error) {
params := make(map[string]string)
if q == "" {
return nil, errors.New("You must provide search query.")
}
params["q"] = q
if limit > 0 {
params["limit"] = strconv.Itoa(limit)
}
if cursor != "" {
params["cursor"] = cursor
}
res := new(ShipmentList)
_, err := get(p, "v1", "shipments/search", params, &res)
// Set Postmaster "base" object for each shipment, so we can use API with them
for k, _ := range res.Results {
res.Results[k].p = p
}
return res, err
}