Skip to content

Commit e6e27ec

Browse files
feat: added v3 shipping options
1 parent 5f77985 commit e6e27ec

File tree

3 files changed

+265
-0
lines changed

3 files changed

+265
-0
lines changed

client/api.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package client
33
import (
44
"github.com/afosto/sendcloud-go/integration"
55
"github.com/afosto/sendcloud-go/method"
6+
"github.com/afosto/sendcloud-go/option"
67
"github.com/afosto/sendcloud-go/parcel"
78
"github.com/afosto/sendcloud-go/products"
89
"github.com/afosto/sendcloud-go/returns"
@@ -18,6 +19,7 @@ type API struct {
1819
Integration *integration.Client
1920
Return *returns.Client
2021
Product *products.Client
22+
Option *option.Client
2123
}
2224

2325
// Initialize the client
@@ -29,4 +31,5 @@ func (a *API) Init(apiKey string, apiSecret string) {
2931
a.Integration = integration.New(apiKey, apiSecret)
3032
a.Return = returns.New(apiKey, apiSecret)
3133
a.Product = products.New(apiKey, apiSecret)
34+
a.Option = option.New(apiKey, apiSecret)
3235
}

option.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package sendcloud
2+
3+
import (
4+
"encoding/json"
5+
)
6+
7+
// OptionParams represents the parameters for fetching shipping options.
8+
// For the simplified client methods (GetDeliveryShippingOptions, GetReturnShippingOptions),
9+
// only Functionalities.Returns will be set.
10+
type OptionParams struct {
11+
FromCountryCode *string `json:"from_country_code,omitempty"`
12+
ToCountryCode *string `json:"to_country_code,omitempty"`
13+
Functionalities *FunctionalityFilter `json:"functionalities,omitempty"`
14+
CarrierCode *string `json:"carrier_code,omitempty"`
15+
ContractID *int64 `json:"contract_id,omitempty"`
16+
ShippingProductCode *string `json:"shipping_product_code,omitempty"`
17+
Dimensions *OptionDimension `json:"dimensions,omitempty"` // For request body
18+
Weight *OptionWeight `json:"weight,omitempty"` // For request body
19+
FromPostalCode *string `json:"from_postal_code,omitempty"`
20+
ToPostalCode *string `json:"to_postal_code,omitempty"`
21+
TotalInsurance *float64 `json:"total_insurance,omitempty"`
22+
LeadTime *LeadTimeFilter `json:"lead_time,omitempty"`
23+
}
24+
25+
// FunctionalityFilter allows specifying functionality-based filters.
26+
// For the simplified client, only 'Returns' will be used.
27+
type FunctionalityFilter struct {
28+
Returns *bool `json:"returns,omitempty"`
29+
// You can add other functionality filters here if needed for more advanced use cases
30+
// e.g., Signature *bool `json:"signature,omitempty"`
31+
}
32+
33+
// OptionDimension specifies dimensions for shipping options in a request.
34+
// Values are strings as per the OpenAPI specification for request bodies.
35+
type OptionDimension struct {
36+
Length string `json:"length"`
37+
Width string `json:"width"`
38+
Height string `json:"height"`
39+
Unit string `json:"unit"` // e.g., "cm", "m"
40+
}
41+
42+
// OptionWeight specifies weight for shipping options in a request.
43+
// Value is a string as per the OpenAPI specification for request bodies.
44+
type OptionWeight struct {
45+
Value string `json:"value"` // e.g. "2.0"
46+
Unit string `json:"unit"` // e.g., "kg", "g"
47+
}
48+
49+
// LeadTimeFilter allows filtering shipping options based on lead time.
50+
type LeadTimeFilter struct {
51+
GT *float64 `json:"gt,omitempty"`
52+
GTE *float64 `json:"gte,omitempty"`
53+
EQ *float64 `json:"eq,omitempty"`
54+
LT *float64 `json:"lt,omitempty"`
55+
LTE *float64 `json:"lte,omitempty"`
56+
}
57+
58+
// GetPayload returns the OptionParams itself, as it directly matches the API request body structure.
59+
func (p *OptionParams) GetPayload() interface{} {
60+
return p
61+
}
62+
63+
// --- Response Structs (to parse the API response) ---
64+
65+
// OptionResponse is the top-level structure for the shipping options API response.
66+
type OptionResponse struct {
67+
Data []*ShippingOption `json:"data"` // 'data' can be an array or null according to API spec.
68+
}
69+
70+
// SetResponse unmarshals the API response body into the OptionResponse struct.
71+
func (r *OptionResponse) SetResponse(body []byte) error {
72+
return json.Unmarshal(body, r)
73+
}
74+
75+
// GetResponse returns the OptionResponse struct itself.
76+
func (r *OptionResponse) GetResponse() interface{} {
77+
return r
78+
}
79+
80+
// ShippingOption represents a single shipping option with its details, pricing, and functionalities.
81+
type ShippingOption struct {
82+
Code string `json:"code,omitempty"`
83+
Carrier *CarrierOption `json:"carrier,omitempty"`
84+
Product *ShippingProduct `json:"product,omitempty"`
85+
Functionalities *CarrierShippingFunctionalities `json:"functionalities,omitempty"` // Response struct for functionalities
86+
MaxDimensions *ResponseDimension `json:"max_dimensions,omitempty"` // Response struct for dimensions
87+
Weight *ShippingOptionWeightRange `json:"weight,omitempty"`
88+
BilledWeight *BilledWeight `json:"billed_weight,omitempty"`
89+
Contract *Contract `json:"contract,omitempty"`
90+
Requirements *Requirements `json:"requirements,omitempty"`
91+
Quotes []*ShippingQuote `json:"quotes"` // Can be null from API, unmarshals to nil slice
92+
}
93+
94+
// Carrier represents carrier information.
95+
type CarrierOption struct {
96+
Code string `json:"code,omitempty"`
97+
Name string `json:"name,omitempty"`
98+
}
99+
100+
// ShippingProduct represents product information for a shipping option.
101+
type ShippingProduct struct {
102+
Code string `json:"code,omitempty"`
103+
Name string `json:"name,omitempty"`
104+
}
105+
106+
// CarrierShippingFunctionalities defines various features or attributes of a shipping option from the API response.
107+
// Pointers are used for fields that can be 'null' in the API response.
108+
type CarrierShippingFunctionalities struct {
109+
AgeCheck *int `json:"age_check"`
110+
B2B bool `json:"b2b"`
111+
B2C bool `json:"b2c"`
112+
Boxable bool `json:"boxable"`
113+
BulkyGoods bool `json:"bulky_goods"`
114+
CarrierBillingType string `json:"carrier_billing_type"`
115+
CashOnDelivery *int `json:"cash_on_delivery"`
116+
DangerousGoods bool `json:"dangerous_goods"`
117+
DeliveryAttempts *int `json:"delivery_attempts"`
118+
DeliveryBefore string `json:"delivery_before"`
119+
DeliveryDeadline string `json:"delivery_deadline"`
120+
EcoDelivery bool `json:"eco_delivery"`
121+
ERS bool `json:"ers"`
122+
FirstMile string `json:"first_mile"`
123+
FlexDelivery bool `json:"flex_delivery"`
124+
FormFactor *string `json:"form_factor"`
125+
FragileGoods bool `json:"fragile_goods"`
126+
FreshGoods bool `json:"fresh_goods"`
127+
HarmonizedLabel bool `json:"harmonized_label"`
128+
IDCheck bool `json:"id_check"`
129+
Incoterm string `json:"incoterm"`
130+
Insurance *int `json:"insurance"`
131+
Labelless bool `json:"labelless"`
132+
LastMile string `json:"last_mile"`
133+
Manually bool `json:"manually"`
134+
Multicollo bool `json:"multicollo"`
135+
NeighborDelivery bool `json:"neighbor_delivery"`
136+
NonConveyable bool `json:"non_conveyable"`
137+
PersonalizedDelivery bool `json:"personalized_delivery"`
138+
PickUp bool `json:"pick_up"`
139+
Premium bool `json:"premium"`
140+
Priority string `json:"priority"`
141+
RegisteredDelivery bool `json:"registered_delivery"`
142+
Returns bool `json:"returns"`
143+
Segment string `json:"segment"`
144+
ServiceArea string `json:"service_area"`
145+
Signature bool `json:"signature"`
146+
Size string `json:"size"`
147+
Sorted bool `json:"sorted"`
148+
Surcharge bool `json:"surcharge"`
149+
Tracked bool `json:"tracked"`
150+
Tyres bool `json:"tyres"`
151+
WeekendDelivery string `json:"weekend_delivery"`
152+
}
153+
154+
// ResponseDimension specifies dimensions from an API response.
155+
// Values are strings as per the OpenAPI specification.
156+
type ResponseDimension struct {
157+
Length string `json:"length"`
158+
Width string `json:"width"`
159+
Height string `json:"height"`
160+
Unit string `json:"unit"`
161+
}
162+
163+
// ResponseWeight specifies weight from an API response.
164+
// Value is a string as per the OpenAPI specification.
165+
type ResponseWeight struct {
166+
Value string `json:"value"`
167+
Unit string `json:"unit"`
168+
}
169+
170+
// ShippingOptionWeightRange defines the minimum and maximum weight for a shipping option.
171+
type ShippingOptionWeightRange struct {
172+
Min *ResponseWeight `json:"min,omitempty"`
173+
Max *ResponseWeight `json:"max,omitempty"`
174+
}
175+
176+
// BilledWeight indicates the weight used for billing, considering volumetric weight.
177+
type BilledWeight struct {
178+
Value string `json:"value"`
179+
Unit string `json:"unit"`
180+
Volumetric bool `json:"volumetric"`
181+
}
182+
183+
// Contract represents a carrier contract.
184+
type Contract struct {
185+
ID int64 `json:"id,omitempty"`
186+
ClientID string `json:"client_id,omitempty"`
187+
CarrierCode string `json:"carrier_code,omitempty"`
188+
Name string `json:"name,omitempty"`
189+
}
190+
191+
// Requirements indicate necessary fields or documents for a shipping option.
192+
type Requirements struct {
193+
Fields []string `json:"fields,omitempty"`
194+
ExportDocuments bool `json:"export_documents"`
195+
}
196+
197+
// ShippingQuote provides pricing details for a shipping option within a specific weight range.
198+
type ShippingQuote struct {
199+
Weight QuoteWeightRange `json:"weight,omitempty"`
200+
LeadTime *int `json:"lead_time,omitempty"` // API spec: integer or null
201+
Price QuotePrice `json:"price,omitempty"`
202+
}
203+
204+
// QuoteWeightRange defines the weight range for a specific quote.
205+
type QuoteWeightRange struct {
206+
Min ResponseWeight `json:"min,omitempty"`
207+
Max ResponseWeight `json:"max,omitempty"`
208+
}
209+
210+
// QuotePrice contains the total price and its breakdown for a shipping quote.
211+
type QuotePrice struct {
212+
Breakdown []*ShippingPriceBreakdownItem `json:"breakdown,omitempty"`
213+
Total *ResponsePrice `json:"total,omitempty"`
214+
}
215+
216+
// ShippingPriceBreakdownItem details a component of the shipping price.
217+
type ShippingPriceBreakdownItem struct {
218+
Type string `json:"type,omitempty"`
219+
Label string `json:"label,omitempty"`
220+
Price *ResponsePrice `json:"price,omitempty"`
221+
}
222+
223+
// ResponsePrice represents a monetary value with currency from an API response.
224+
// Value is a string as per the OpenAPI specification.
225+
type ResponsePrice struct {
226+
Value string `json:"value"`
227+
Currency string `json:"currency"`
228+
}
229+
230+
// Helper functions for creating pointers.
231+
// Useful if constructing OptionParams manually with more specific filters.
232+
func Bool(b bool) *bool { v := b; return &v }
233+
func String(s string) *string { v := s; return &v }
234+
func Int(i int) *int { v := i; return &v }
235+
func Int64(i int64) *int64 { v := i; return &v }
236+
func Float64(f float64) *float64 { v := f; return &v }

option/client.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package option
2+
3+
import (
4+
"github.com/afosto/sendcloud-go"
5+
)
6+
7+
type Client struct {
8+
apiKey string
9+
apiSecret string
10+
}
11+
12+
func New(apiKey string, apiSecret string) *Client {
13+
return &Client{
14+
apiKey: apiKey,
15+
apiSecret: apiSecret,
16+
}
17+
}
18+
19+
func (c *Client) GetShippingOptions(params *sendcloud.OptionParams) (*sendcloud.OptionResponse, error) {
20+
response := sendcloud.OptionResponse{}
21+
err := sendcloud.Request("POST", "/api/v3/fetch-shipping-options", params, c.apiKey, c.apiSecret, &response)
22+
if err != nil {
23+
return nil, err
24+
}
25+
return response.GetResponse().(*sendcloud.OptionResponse), nil
26+
}

0 commit comments

Comments
 (0)