aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2026-07-29 14:59:34 -0230
committerSam Anthony <sam@samanthony.xyz>2026-07-29 14:59:34 -0230
commitc0467b88c2a8a70b15e0ed7549863bafcac266ea (patch)
tree46e904f5a60f75eb88b80f44c293b40072c50a5b
parent0594075ecc77c672f33ce9e36dbf1c1a6c89ccb7 (diff)
downloadlulu-c0467b88c2a8a70b15e0ed7549863bafcac266ea.zip
shipping addresses: mark optional fields omitempty/omitzero
-rw-r--r--cmd/lulu/ship.go8
-rw-r--r--ship.go78
-rw-r--r--ship_test.go61
-rw-r--r--testdata/printreq.json8
-rw-r--r--testdata/reprintreq.json8
5 files changed, 42 insertions, 121 deletions
diff --git a/cmd/lulu/ship.go b/cmd/lulu/ship.go
index f33aeaa..756c392 100644
--- a/cmd/lulu/ship.go
+++ b/cmd/lulu/ship.go
@@ -3,8 +3,8 @@ package main
import "git.samanthony.xyz/lulu"
type ShippingAddress struct {
- Country string `required help:"2-letter country code"`
- State string `help:"2- or 3-letter state/subdivision code"`
+ CountryCode string `required help:"2-letter country code" name:"country"`
+ StateCode string `help:"2- or 3-letter state/subdivision code" name:"state"`
City string `required`
Street1 string `required name:"street1"`
Street2 string `name:"street2"`
@@ -20,8 +20,8 @@ type ShippingAddress struct {
func (addr ShippingAddress) Addr() lulu.ShippingAddress {
return lulu.ShippingAddress{
- Country: addr.Country,
- State: addr.State,
+ CountryCode: addr.CountryCode,
+ StateCode: addr.StateCode,
City: addr.City,
Street1: addr.Street1,
Street2: addr.Street2,
diff --git a/ship.go b/ship.go
index 2d54d07..974d792 100644
--- a/ship.go
+++ b/ship.go
@@ -30,33 +30,33 @@ const (
type ShippingAddress struct {
// ISO 3166-2 country code
- Country string `json:"country_code"`
+ CountryCode string `json:"country_code"`
// 2 or 3 letter state code (officially called ISO-3166-2
// subdivision codes). They are required for some countries (e.g.
// US, MX, CA, AU).
- State string `json:"state_code"`
+ StateCode string `json:"state_code"`
City string `json:"city"`
- Street1 string `json:"street1"` // First address line
- Street2 string `json:"street2"` // Second address line
- PostCode string `json:"postcode"` // Required for most countries
+ Street1 string `json:"street1"` // First address line
+ Street2 string `json:"street2,omitempty"` // Second address line
+ PostCode string `json:"postcode"` // Required for most countries
// Only relevant for US addresses. Some US carriers don't deliver
// to business-addresses on Saturday.
- IsBusiness bool `json:"is_business"`
+ IsBusiness bool `json:"is_business,omitempty"`
// Full name of the person, including first and last name.
- Name string `json:"name"`
- Title Title `json:"title"`
+ Name string `json:"name,omitempty"`
+ Title Title `json:"title,omitempty"`
// Name of an organization. Required if no person name is given.
- Organization string `json:"organization"`
+ Organization string `json:"organization,omitempty"`
// Shipping carriers require an email address for notifications
// or handling delivery issues. If no email is given, the default
// email in the user profile will be used.
- Email EmailAddress `json:"email"`
+ Email EmailAddress `json:"email,omitzero"`
// Shipping carriers require a phone number for handling delivery
// issues. If no phone number is given, the default in the API
@@ -65,10 +65,10 @@ type ShippingAddress struct {
// The recipient's tax identification number. Required for
// shipping addresses to Brazil, Chile, and Mexico.
- TaxId string `json:"recipient_tax_id"`
+ TaxId string `json:"recipient_tax_id,omitempty"`
}
-func (a *ShippingAddress) UnmarshalJSON(data []byte) error {
+func unmarshalShippingAddressJSON(data []byte, ap *ShippingAddress) error {
var alias extShippingAddress
if err := json.Unmarshal(data, &alias); err != nil {
return err
@@ -77,7 +77,7 @@ func (a *ShippingAddress) UnmarshalJSON(data []byte) error {
if err != nil {
return err
}
- *a = addr
+ *ap = addr
return nil
}
@@ -114,28 +114,14 @@ type ShippingAddressWarning struct {
// also unmarshals either "country" or "country_code" etc. to account for
// the irregularities in the API.
type extShippingAddress struct {
- Country string `json:"country"`
- CountryCode string `json:"country_code"`
+ ShippingAddress
- State string `json:"state"`
- StateCode string `json:"state_code"`
+ Country string `json:"country"`
+ State string `json:"state"`
- City string `json:"city"`
- Street1 string `json:"street1"`
- Street2 string `json:"street2"`
- PostCode string `json:"postcode"`
- IsBusiness bool `json:"is_business"`
-
- Name string `json:"name"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
- Title Title `json:"title"`
- Organization string `json:"organization"`
- Email EmailAddress `json:"email"`
- Phone PhoneNumber `json:"phone_number"`
- TaxId string `json:"recipient_tax_id"`
-
Warnings []ShippingAddressWarning `json:"warnings"`
Suggested ShippingAddress `json:"suggested_address"`
}
@@ -146,47 +132,33 @@ type extShippingAddress struct {
// It returns error if two or more of the "same field" are present, eg.
// both "country" and "country_code".
func (ext extShippingAddress) addr() (ShippingAddress, error) {
+ addr := ext.ShippingAddress
+
country, both := either(ext.Country, ext.CountryCode)
if both {
return ShippingAddress{}, fmt.Errorf(`address contains both "country" and "country_code"`)
}
+ addr.CountryCode = country
state, both := either(ext.State, ext.StateCode)
if both {
return ShippingAddress{}, fmt.Errorf(`address contains both "state" and "state_code"`)
}
+ addr.StateCode = state
- var name string
- hasName := ext.Name != ""
hasFirst := ext.FirstName != ""
hasLast := ext.LastName != ""
- if hasName && (hasFirst || hasLast) {
+ if addr.Name != "" && (hasFirst || hasLast) {
return ShippingAddress{}, fmt.Errorf(`address contains both "name" and {"first_name", "last_name"}`)
- } else if hasName {
- name = ext.Name
} else if hasFirst && hasLast {
- name = fmt.Sprintf("%s %s", ext.FirstName, ext.LastName)
+ addr.Name = fmt.Sprintf("%s %s", ext.FirstName, ext.LastName)
} else if hasLast {
- name = ext.LastName
+ addr.Name = ext.LastName
} else if hasFirst {
- name = ext.FirstName
+ addr.Name = ext.FirstName
}
- return ShippingAddress{
- Country: country,
- State: state,
- City: ext.City,
- Street1: ext.Street1,
- Street2: ext.Street2,
- PostCode: ext.PostCode,
- IsBusiness: ext.IsBusiness,
- Name: name,
- Title: ext.Title,
- Organization: ext.Organization,
- Email: ext.Email,
- Phone: ext.Phone,
- TaxId: ext.TaxId,
- }, nil
+ return addr, nil
}
func either(a, b string) (string, bool) {
diff --git a/ship_test.go b/ship_test.go
index bd5432d..a90f22f 100644
--- a/ship_test.go
+++ b/ship_test.go
@@ -3,23 +3,19 @@ package lulu
import (
_ "embed"
"testing"
-
- "github.com/stretchr/testify/require"
)
//go:embed testdata/shipaddrresp.json
var shipAddrRespJson string
var shipAddrSample = ShippingAddress{
- City: "Lübeck",
- Country: "DE",
- IsBusiness: false,
- Name: "Hans Dampf",
- Phone: MustParsePhoneNumber("844-212-0689"),
- PostCode: "23552",
- State: "",
- Street1: "Holstenstr. 40",
- Street2: "",
+ City: "Lübeck",
+ CountryCode: "DE",
+ IsBusiness: false,
+ Name: "Hans Dampf",
+ Phone: MustParsePhoneNumber("844-212-0689"),
+ PostCode: "23552",
+ Street1: "Holstenstr. 40",
}
var shipWarningsSample = []ShippingAddressWarning{{
Type: "validation_warning",
@@ -28,11 +24,10 @@ var shipWarningsSample = []ShippingAddressWarning{{
Msg: "street1: Holstenstr. 40 -> Holstenstraße 40",
}}
var suggestedShipAddrSample = ShippingAddress{
- Country: "DE",
- State: "",
- PostCode: "23552",
- City: "Lübeck",
- Street1: "Holstenstraße 40",
+ CountryCode: "DE",
+ PostCode: "23552",
+ City: "Lübeck",
+ Street1: "Holstenstraße 40",
}
var shipAddrValidationSample = ShippingAddressValidation{
Address: shipAddrSample,
@@ -43,37 +38,3 @@ var shipAddrValidationSample = ShippingAddressValidation{
func TestUnmarshalShippingAddressValidation(t *testing.T) {
requireUnmarshalJsonEq(t, shipAddrValidationSample, shipAddrRespJson)
}
-
-func requireMatchShipAddrValidationSample(t *testing.T, av ShippingAddressValidation) {
- t.Helper()
- requireMatchShipAddrSample(t, av.Address)
- requireMatchShipWarningsSample(t, av.Warnings)
- requireMatchSuggestedShipAddrSample(t, av.Suggested)
-}
-
-func requireMatchShipAddrSample(t *testing.T, addr ShippingAddress) {
- t.Helper()
- require.Equal(t, shipAddrSample.City, addr.City)
- require.Equal(t, shipAddrSample.Country, addr.Country)
- require.Equal(t, shipAddrSample.IsBusiness, addr.IsBusiness)
- require.Equal(t, shipAddrSample.Name, addr.Name)
- require.Equal(t, shipAddrSample.Phone, addr.Phone)
- require.Equal(t, shipAddrSample.PostCode, addr.PostCode)
- require.Equal(t, shipAddrSample.State, addr.State)
- require.Equal(t, shipAddrSample.Street1, addr.Street1)
- require.Equal(t, shipAddrSample.Street2, addr.Street2)
-}
-
-func requireMatchShipWarningsSample(t *testing.T, warns []ShippingAddressWarning) {
- t.Helper()
- require.Equal(t, shipWarningsSample, warns)
-}
-
-func requireMatchSuggestedShipAddrSample(t *testing.T, sug ShippingAddress) {
- t.Helper()
- require.Equal(t, suggestedShipAddrSample.Country, sug.Country)
- require.Equal(t, suggestedShipAddrSample.State, sug.State)
- require.Equal(t, suggestedShipAddrSample.PostCode, sug.PostCode)
- require.Equal(t, suggestedShipAddrSample.City, sug.City)
- require.Equal(t, suggestedShipAddrSample.Street1, sug.Street1)
-}
diff --git a/testdata/printreq.json b/testdata/printreq.json
index c1bde40..41f6bf4 100644
--- a/testdata/printreq.json
+++ b/testdata/printreq.json
@@ -19,13 +19,7 @@
"phone_number": "844-212-0689",
"postcode": "23552",
"state_code": "",
- "street1": "Holstenstr. 40",
- "street2": "",
- "email": "",
- "title": "",
- "is_business": false,
- "organization": "",
- "recipient_tax_id": ""
+ "street1": "Holstenstr. 40"
},
"shipping_level": "MAIL"
}
diff --git a/testdata/reprintreq.json b/testdata/reprintreq.json
index 75544cd..0539428 100644
--- a/testdata/reprintreq.json
+++ b/testdata/reprintreq.json
@@ -17,13 +17,7 @@
"phone_number": "844-212-0689",
"postcode": "23552",
"state_code": "",
- "street1": "Holstenstr. 40",
- "street2": "",
- "email": "",
- "title": "",
- "is_business": false,
- "organization": "",
- "recipient_tax_id": ""
+ "street1": "Holstenstr. 40"
},
"shipping_level": "MAIL"
}