From c0467b88c2a8a70b15e0ed7549863bafcac266ea Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Wed, 29 Jul 2026 14:59:34 -0230 Subject: shipping addresses: mark optional fields omitempty/omitzero --- cmd/lulu/ship.go | 8 ++--- ship.go | 78 ++++++++++++++++-------------------------------- ship_test.go | 61 +++++++------------------------------ testdata/printreq.json | 8 +---- testdata/reprintreq.json | 8 +---- 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" } -- cgit v1.2.3