diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 41eff19a2c4..25e29b3ff64 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -7216,7 +7216,7 @@ func init() { "destinationAddress": { "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, @@ -10765,6 +10765,179 @@ func init() { } } }, + "PPMDestinationAddress": { + "description": "A postal address", + "type": "object", + "required": [ + "city", + "state", + "postalCode" + ], + "properties": { + "city": { + "type": "string", + "title": "City", + "example": "Anytown" + }, + "country": { + "type": "string", + "title": "Country", + "default": "USA", + "x-nullable": true, + "example": "USA" + }, + "county": { + "type": "string", + "title": "County", + "x-nullable": true, + "example": "LOS ANGELES" + }, + "eTag": { + "type": "string", + "readOnly": true + }, + "id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, + "postalCode": { + "type": "string", + "format": "zip", + "title": "ZIP", + "pattern": "^(\\d{5}([\\-]\\d{4})?)$", + "example": "90210" + }, + "state": { + "type": "string", + "title": "State", + "enum": [ + "AL", + "AK", + "AR", + "AZ", + "CA", + "CO", + "CT", + "DC", + "DE", + "FL", + "GA", + "HI", + "IA", + "ID", + "IL", + "IN", + "KS", + "KY", + "LA", + "MA", + "MD", + "ME", + "MI", + "MN", + "MO", + "MS", + "MT", + "NC", + "ND", + "NE", + "NH", + "NJ", + "NM", + "NV", + "NY", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VA", + "VT", + "WA", + "WI", + "WV", + "WY" + ], + "x-display-value": { + "AK": "AK", + "AL": "AL", + "AR": "AR", + "AZ": "AZ", + "CA": "CA", + "CO": "CO", + "CT": "CT", + "DC": "DC", + "DE": "DE", + "FL": "FL", + "GA": "GA", + "HI": "HI", + "IA": "IA", + "ID": "ID", + "IL": "IL", + "IN": "IN", + "KS": "KS", + "KY": "KY", + "LA": "LA", + "MA": "MA", + "MD": "MD", + "ME": "ME", + "MI": "MI", + "MN": "MN", + "MO": "MO", + "MS": "MS", + "MT": "MT", + "NC": "NC", + "ND": "ND", + "NE": "NE", + "NH": "NH", + "NJ": "NJ", + "NM": "NM", + "NV": "NV", + "NY": "NY", + "OH": "OH", + "OK": "OK", + "OR": "OR", + "PA": "PA", + "RI": "RI", + "SC": "SC", + "SD": "SD", + "TN": "TN", + "TX": "TX", + "UT": "UT", + "VA": "VA", + "VT": "VT", + "WA": "WA", + "WI": "WI", + "WV": "WV", + "WY": "WY" + } + }, + "streetAddress1": { + "type": "string", + "title": "Street address 1", + "x-nullable": true, + "example": "123 Main Ave" + }, + "streetAddress2": { + "type": "string", + "title": "Street address 2", + "x-nullable": true, + "example": "Apartment 9000" + }, + "streetAddress3": { + "type": "string", + "title": "Address Line 3", + "x-nullable": true, + "example": "Montmârtre" + } + } + }, "PPMDocumentStatus": { "description": "Status of the PPM document.", "type": "string", @@ -13414,7 +13587,7 @@ func init() { "destinationAddress": { "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, @@ -22910,7 +23083,7 @@ func init() { "destinationAddress": { "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, @@ -26460,6 +26633,179 @@ func init() { } } }, + "PPMDestinationAddress": { + "description": "A postal address", + "type": "object", + "required": [ + "city", + "state", + "postalCode" + ], + "properties": { + "city": { + "type": "string", + "title": "City", + "example": "Anytown" + }, + "country": { + "type": "string", + "title": "Country", + "default": "USA", + "x-nullable": true, + "example": "USA" + }, + "county": { + "type": "string", + "title": "County", + "x-nullable": true, + "example": "LOS ANGELES" + }, + "eTag": { + "type": "string", + "readOnly": true + }, + "id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, + "postalCode": { + "type": "string", + "format": "zip", + "title": "ZIP", + "pattern": "^(\\d{5}([\\-]\\d{4})?)$", + "example": "90210" + }, + "state": { + "type": "string", + "title": "State", + "enum": [ + "AL", + "AK", + "AR", + "AZ", + "CA", + "CO", + "CT", + "DC", + "DE", + "FL", + "GA", + "HI", + "IA", + "ID", + "IL", + "IN", + "KS", + "KY", + "LA", + "MA", + "MD", + "ME", + "MI", + "MN", + "MO", + "MS", + "MT", + "NC", + "ND", + "NE", + "NH", + "NJ", + "NM", + "NV", + "NY", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VA", + "VT", + "WA", + "WI", + "WV", + "WY" + ], + "x-display-value": { + "AK": "AK", + "AL": "AL", + "AR": "AR", + "AZ": "AZ", + "CA": "CA", + "CO": "CO", + "CT": "CT", + "DC": "DC", + "DE": "DE", + "FL": "FL", + "GA": "GA", + "HI": "HI", + "IA": "IA", + "ID": "ID", + "IL": "IL", + "IN": "IN", + "KS": "KS", + "KY": "KY", + "LA": "LA", + "MA": "MA", + "MD": "MD", + "ME": "ME", + "MI": "MI", + "MN": "MN", + "MO": "MO", + "MS": "MS", + "MT": "MT", + "NC": "NC", + "ND": "ND", + "NE": "NE", + "NH": "NH", + "NJ": "NJ", + "NM": "NM", + "NV": "NV", + "NY": "NY", + "OH": "OH", + "OK": "OK", + "OR": "OR", + "PA": "PA", + "RI": "RI", + "SC": "SC", + "SD": "SD", + "TN": "TN", + "TX": "TX", + "UT": "UT", + "VA": "VA", + "VT": "VT", + "WA": "WA", + "WI": "WI", + "WV": "WV", + "WY": "WY" + } + }, + "streetAddress1": { + "type": "string", + "title": "Street address 1", + "x-nullable": true, + "example": "123 Main Ave" + }, + "streetAddress2": { + "type": "string", + "title": "Street address 2", + "x-nullable": true, + "example": "Apartment 9000" + }, + "streetAddress3": { + "type": "string", + "title": "Address Line 3", + "x-nullable": true, + "example": "Montmârtre" + } + } + }, "PPMDocumentStatus": { "description": "Status of the PPM document.", "type": "string", @@ -29239,7 +29585,7 @@ func init() { "destinationAddress": { "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, diff --git a/pkg/gen/ghcmessages/create_p_p_m_shipment.go b/pkg/gen/ghcmessages/create_p_p_m_shipment.go index ca8bcf541c5..15178bcc082 100644 --- a/pkg/gen/ghcmessages/create_p_p_m_shipment.go +++ b/pkg/gen/ghcmessages/create_p_p_m_shipment.go @@ -22,7 +22,7 @@ type CreatePPMShipment struct { // destination address // Required: true DestinationAddress struct { - Address + PPMDestinationAddress } `json:"destinationAddress"` // estimated weight diff --git a/pkg/gen/ghcmessages/p_p_m_destination_address.go b/pkg/gen/ghcmessages/p_p_m_destination_address.go new file mode 100644 index 00000000000..4a5b9d2fa82 --- /dev/null +++ b/pkg/gen/ghcmessages/p_p_m_destination_address.go @@ -0,0 +1,358 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ghcmessages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// PPMDestinationAddress A postal address +// +// swagger:model PPMDestinationAddress +type PPMDestinationAddress struct { + + // City + // Example: Anytown + // Required: true + City *string `json:"city"` + + // Country + // Example: USA + Country *string `json:"country,omitempty"` + + // County + // Example: LOS ANGELES + County *string `json:"county,omitempty"` + + // e tag + // Read Only: true + ETag string `json:"eTag,omitempty"` + + // id + // Example: c56a4180-65aa-42ec-a945-5fd21dec0538 + // Format: uuid + ID strfmt.UUID `json:"id,omitempty"` + + // ZIP + // Example: 90210 + // Required: true + // Pattern: ^(\d{5}([\-]\d{4})?)$ + PostalCode *string `json:"postalCode"` + + // State + // Required: true + // Enum: [AL AK AR AZ CA CO CT DC DE FL GA HI IA ID IL IN KS KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY] + State *string `json:"state"` + + // Street address 1 + // Example: 123 Main Ave + StreetAddress1 *string `json:"streetAddress1,omitempty"` + + // Street address 2 + // Example: Apartment 9000 + StreetAddress2 *string `json:"streetAddress2,omitempty"` + + // Address Line 3 + // Example: Montmârtre + StreetAddress3 *string `json:"streetAddress3,omitempty"` +} + +// Validate validates this p p m destination address +func (m *PPMDestinationAddress) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCity(formats); err != nil { + res = append(res, err) + } + + if err := m.validateID(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePostalCode(formats); err != nil { + res = append(res, err) + } + + if err := m.validateState(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PPMDestinationAddress) validateCity(formats strfmt.Registry) error { + + if err := validate.Required("city", "body", m.City); err != nil { + return err + } + + return nil +} + +func (m *PPMDestinationAddress) validateID(formats strfmt.Registry) error { + if swag.IsZero(m.ID) { // not required + return nil + } + + if err := validate.FormatOf("id", "body", "uuid", m.ID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *PPMDestinationAddress) validatePostalCode(formats strfmt.Registry) error { + + if err := validate.Required("postalCode", "body", m.PostalCode); err != nil { + return err + } + + if err := validate.Pattern("postalCode", "body", *m.PostalCode, `^(\d{5}([\-]\d{4})?)$`); err != nil { + return err + } + + return nil +} + +var pPMDestinationAddressTypeStatePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["AL","AK","AR","AZ","CA","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL","IN","KS","KY","LA","MA","MD","ME","MI","MN","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VA","VT","WA","WI","WV","WY"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + pPMDestinationAddressTypeStatePropEnum = append(pPMDestinationAddressTypeStatePropEnum, v) + } +} + +const ( + + // PPMDestinationAddressStateAL captures enum value "AL" + PPMDestinationAddressStateAL string = "AL" + + // PPMDestinationAddressStateAK captures enum value "AK" + PPMDestinationAddressStateAK string = "AK" + + // PPMDestinationAddressStateAR captures enum value "AR" + PPMDestinationAddressStateAR string = "AR" + + // PPMDestinationAddressStateAZ captures enum value "AZ" + PPMDestinationAddressStateAZ string = "AZ" + + // PPMDestinationAddressStateCA captures enum value "CA" + PPMDestinationAddressStateCA string = "CA" + + // PPMDestinationAddressStateCO captures enum value "CO" + PPMDestinationAddressStateCO string = "CO" + + // PPMDestinationAddressStateCT captures enum value "CT" + PPMDestinationAddressStateCT string = "CT" + + // PPMDestinationAddressStateDC captures enum value "DC" + PPMDestinationAddressStateDC string = "DC" + + // PPMDestinationAddressStateDE captures enum value "DE" + PPMDestinationAddressStateDE string = "DE" + + // PPMDestinationAddressStateFL captures enum value "FL" + PPMDestinationAddressStateFL string = "FL" + + // PPMDestinationAddressStateGA captures enum value "GA" + PPMDestinationAddressStateGA string = "GA" + + // PPMDestinationAddressStateHI captures enum value "HI" + PPMDestinationAddressStateHI string = "HI" + + // PPMDestinationAddressStateIA captures enum value "IA" + PPMDestinationAddressStateIA string = "IA" + + // PPMDestinationAddressStateID captures enum value "ID" + PPMDestinationAddressStateID string = "ID" + + // PPMDestinationAddressStateIL captures enum value "IL" + PPMDestinationAddressStateIL string = "IL" + + // PPMDestinationAddressStateIN captures enum value "IN" + PPMDestinationAddressStateIN string = "IN" + + // PPMDestinationAddressStateKS captures enum value "KS" + PPMDestinationAddressStateKS string = "KS" + + // PPMDestinationAddressStateKY captures enum value "KY" + PPMDestinationAddressStateKY string = "KY" + + // PPMDestinationAddressStateLA captures enum value "LA" + PPMDestinationAddressStateLA string = "LA" + + // PPMDestinationAddressStateMA captures enum value "MA" + PPMDestinationAddressStateMA string = "MA" + + // PPMDestinationAddressStateMD captures enum value "MD" + PPMDestinationAddressStateMD string = "MD" + + // PPMDestinationAddressStateME captures enum value "ME" + PPMDestinationAddressStateME string = "ME" + + // PPMDestinationAddressStateMI captures enum value "MI" + PPMDestinationAddressStateMI string = "MI" + + // PPMDestinationAddressStateMN captures enum value "MN" + PPMDestinationAddressStateMN string = "MN" + + // PPMDestinationAddressStateMO captures enum value "MO" + PPMDestinationAddressStateMO string = "MO" + + // PPMDestinationAddressStateMS captures enum value "MS" + PPMDestinationAddressStateMS string = "MS" + + // PPMDestinationAddressStateMT captures enum value "MT" + PPMDestinationAddressStateMT string = "MT" + + // PPMDestinationAddressStateNC captures enum value "NC" + PPMDestinationAddressStateNC string = "NC" + + // PPMDestinationAddressStateND captures enum value "ND" + PPMDestinationAddressStateND string = "ND" + + // PPMDestinationAddressStateNE captures enum value "NE" + PPMDestinationAddressStateNE string = "NE" + + // PPMDestinationAddressStateNH captures enum value "NH" + PPMDestinationAddressStateNH string = "NH" + + // PPMDestinationAddressStateNJ captures enum value "NJ" + PPMDestinationAddressStateNJ string = "NJ" + + // PPMDestinationAddressStateNM captures enum value "NM" + PPMDestinationAddressStateNM string = "NM" + + // PPMDestinationAddressStateNV captures enum value "NV" + PPMDestinationAddressStateNV string = "NV" + + // PPMDestinationAddressStateNY captures enum value "NY" + PPMDestinationAddressStateNY string = "NY" + + // PPMDestinationAddressStateOH captures enum value "OH" + PPMDestinationAddressStateOH string = "OH" + + // PPMDestinationAddressStateOK captures enum value "OK" + PPMDestinationAddressStateOK string = "OK" + + // PPMDestinationAddressStateOR captures enum value "OR" + PPMDestinationAddressStateOR string = "OR" + + // PPMDestinationAddressStatePA captures enum value "PA" + PPMDestinationAddressStatePA string = "PA" + + // PPMDestinationAddressStateRI captures enum value "RI" + PPMDestinationAddressStateRI string = "RI" + + // PPMDestinationAddressStateSC captures enum value "SC" + PPMDestinationAddressStateSC string = "SC" + + // PPMDestinationAddressStateSD captures enum value "SD" + PPMDestinationAddressStateSD string = "SD" + + // PPMDestinationAddressStateTN captures enum value "TN" + PPMDestinationAddressStateTN string = "TN" + + // PPMDestinationAddressStateTX captures enum value "TX" + PPMDestinationAddressStateTX string = "TX" + + // PPMDestinationAddressStateUT captures enum value "UT" + PPMDestinationAddressStateUT string = "UT" + + // PPMDestinationAddressStateVA captures enum value "VA" + PPMDestinationAddressStateVA string = "VA" + + // PPMDestinationAddressStateVT captures enum value "VT" + PPMDestinationAddressStateVT string = "VT" + + // PPMDestinationAddressStateWA captures enum value "WA" + PPMDestinationAddressStateWA string = "WA" + + // PPMDestinationAddressStateWI captures enum value "WI" + PPMDestinationAddressStateWI string = "WI" + + // PPMDestinationAddressStateWV captures enum value "WV" + PPMDestinationAddressStateWV string = "WV" + + // PPMDestinationAddressStateWY captures enum value "WY" + PPMDestinationAddressStateWY string = "WY" +) + +// prop value enum +func (m *PPMDestinationAddress) validateStateEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, pPMDestinationAddressTypeStatePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *PPMDestinationAddress) validateState(formats strfmt.Registry) error { + + if err := validate.Required("state", "body", m.State); err != nil { + return err + } + + // value enum + if err := m.validateStateEnum("state", "body", *m.State); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this p p m destination address based on the context it is used +func (m *PPMDestinationAddress) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateETag(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PPMDestinationAddress) contextValidateETag(ctx context.Context, formats strfmt.Registry) error { + + if err := validate.ReadOnly(ctx, "eTag", "body", string(m.ETag)); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PPMDestinationAddress) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PPMDestinationAddress) UnmarshalBinary(b []byte) error { + var res PPMDestinationAddress + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/gen/ghcmessages/update_p_p_m_shipment.go b/pkg/gen/ghcmessages/update_p_p_m_shipment.go index bdad92b6df2..7291cd321ac 100644 --- a/pkg/gen/ghcmessages/update_p_p_m_shipment.go +++ b/pkg/gen/ghcmessages/update_p_p_m_shipment.go @@ -52,7 +52,7 @@ type UpdatePPMShipment struct { // destination address DestinationAddress struct { - Address + PPMDestinationAddress } `json:"destinationAddress,omitempty"` // estimated weight diff --git a/pkg/gen/internalapi/embedded_spec.go b/pkg/gen/internalapi/embedded_spec.go index 796d9a79a73..a8bb8149824 100644 --- a/pkg/gen/internalapi/embedded_spec.go +++ b/pkg/gen/internalapi/embedded_spec.go @@ -3850,7 +3850,7 @@ func init() { ], "properties": { "destinationAddress": { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" }, "expectedDepartureDate": { "description": "Date the customer expects to move.\n", @@ -6003,6 +6003,179 @@ func init() { ], "x-nullable": true }, + "PPMDestinationAddress": { + "description": "A postal address", + "type": "object", + "required": [ + "city", + "state", + "postalCode" + ], + "properties": { + "city": { + "type": "string", + "title": "City", + "example": "Anytown" + }, + "country": { + "type": "string", + "title": "Country", + "default": "USA", + "x-nullable": true, + "example": "USA" + }, + "county": { + "type": "string", + "title": "County", + "x-nullable": true, + "example": "LOS ANGELES" + }, + "eTag": { + "type": "string", + "readOnly": true + }, + "id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, + "postalCode": { + "type": "string", + "format": "zip", + "title": "ZIP", + "pattern": "^(\\d{5}([\\-]\\d{4})?)$", + "example": "90210" + }, + "state": { + "type": "string", + "title": "State", + "enum": [ + "AL", + "AK", + "AR", + "AZ", + "CA", + "CO", + "CT", + "DC", + "DE", + "FL", + "GA", + "HI", + "IA", + "ID", + "IL", + "IN", + "KS", + "KY", + "LA", + "MA", + "MD", + "ME", + "MI", + "MN", + "MO", + "MS", + "MT", + "NC", + "ND", + "NE", + "NH", + "NJ", + "NM", + "NV", + "NY", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VA", + "VT", + "WA", + "WI", + "WV", + "WY" + ], + "x-display-value": { + "AK": "AK", + "AL": "AL", + "AR": "AR", + "AZ": "AZ", + "CA": "CA", + "CO": "CO", + "CT": "CT", + "DC": "DC", + "DE": "DE", + "FL": "FL", + "GA": "GA", + "HI": "HI", + "IA": "IA", + "ID": "ID", + "IL": "IL", + "IN": "IN", + "KS": "KS", + "KY": "KY", + "LA": "LA", + "MA": "MA", + "MD": "MD", + "ME": "ME", + "MI": "MI", + "MN": "MN", + "MO": "MO", + "MS": "MS", + "MT": "MT", + "NC": "NC", + "ND": "ND", + "NE": "NE", + "NH": "NH", + "NJ": "NJ", + "NM": "NM", + "NV": "NV", + "NY": "NY", + "OH": "OH", + "OK": "OK", + "OR": "OR", + "PA": "PA", + "RI": "RI", + "SC": "SC", + "SD": "SD", + "TN": "TN", + "TX": "TX", + "UT": "UT", + "VA": "VA", + "VT": "VT", + "WA": "WA", + "WI": "WI", + "WV": "WV", + "WY": "WY" + } + }, + "streetAddress1": { + "type": "string", + "title": "Street address 1", + "x-nullable": true, + "example": "123 Main Ave" + }, + "streetAddress2": { + "type": "string", + "title": "Street address 2", + "x-nullable": true, + "example": "Apartment 9000" + }, + "streetAddress3": { + "type": "string", + "title": "Address Line 3", + "x-nullable": true, + "example": "Montmârtre" + } + } + }, "PPMDocumentStatusReason": { "description": "The reason the services counselor has excluded or rejected the item.", "type": "string", @@ -7408,7 +7581,7 @@ func init() { "x-nullable": true }, "destinationAddress": { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" }, "estimatedWeight": { "type": "integer", @@ -12470,7 +12643,7 @@ func init() { ], "properties": { "destinationAddress": { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" }, "expectedDepartureDate": { "description": "Date the customer expects to move.\n", @@ -14627,6 +14800,179 @@ func init() { ], "x-nullable": true }, + "PPMDestinationAddress": { + "description": "A postal address", + "type": "object", + "required": [ + "city", + "state", + "postalCode" + ], + "properties": { + "city": { + "type": "string", + "title": "City", + "example": "Anytown" + }, + "country": { + "type": "string", + "title": "Country", + "default": "USA", + "x-nullable": true, + "example": "USA" + }, + "county": { + "type": "string", + "title": "County", + "x-nullable": true, + "example": "LOS ANGELES" + }, + "eTag": { + "type": "string", + "readOnly": true + }, + "id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, + "postalCode": { + "type": "string", + "format": "zip", + "title": "ZIP", + "pattern": "^(\\d{5}([\\-]\\d{4})?)$", + "example": "90210" + }, + "state": { + "type": "string", + "title": "State", + "enum": [ + "AL", + "AK", + "AR", + "AZ", + "CA", + "CO", + "CT", + "DC", + "DE", + "FL", + "GA", + "HI", + "IA", + "ID", + "IL", + "IN", + "KS", + "KY", + "LA", + "MA", + "MD", + "ME", + "MI", + "MN", + "MO", + "MS", + "MT", + "NC", + "ND", + "NE", + "NH", + "NJ", + "NM", + "NV", + "NY", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VA", + "VT", + "WA", + "WI", + "WV", + "WY" + ], + "x-display-value": { + "AK": "AK", + "AL": "AL", + "AR": "AR", + "AZ": "AZ", + "CA": "CA", + "CO": "CO", + "CT": "CT", + "DC": "DC", + "DE": "DE", + "FL": "FL", + "GA": "GA", + "HI": "HI", + "IA": "IA", + "ID": "ID", + "IL": "IL", + "IN": "IN", + "KS": "KS", + "KY": "KY", + "LA": "LA", + "MA": "MA", + "MD": "MD", + "ME": "ME", + "MI": "MI", + "MN": "MN", + "MO": "MO", + "MS": "MS", + "MT": "MT", + "NC": "NC", + "ND": "ND", + "NE": "NE", + "NH": "NH", + "NJ": "NJ", + "NM": "NM", + "NV": "NV", + "NY": "NY", + "OH": "OH", + "OK": "OK", + "OR": "OR", + "PA": "PA", + "RI": "RI", + "SC": "SC", + "SD": "SD", + "TN": "TN", + "TX": "TX", + "UT": "UT", + "VA": "VA", + "VT": "VT", + "WA": "WA", + "WI": "WI", + "WV": "WV", + "WY": "WY" + } + }, + "streetAddress1": { + "type": "string", + "title": "Street address 1", + "x-nullable": true, + "example": "123 Main Ave" + }, + "streetAddress2": { + "type": "string", + "title": "Street address 2", + "x-nullable": true, + "example": "Apartment 9000" + }, + "streetAddress3": { + "type": "string", + "title": "Address Line 3", + "x-nullable": true, + "example": "Montmârtre" + } + } + }, "PPMDocumentStatusReason": { "description": "The reason the services counselor has excluded or rejected the item.", "type": "string", @@ -16034,7 +16380,7 @@ func init() { "x-nullable": true }, "destinationAddress": { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" }, "estimatedWeight": { "type": "integer", diff --git a/pkg/gen/internalmessages/create_p_p_m_shipment.go b/pkg/gen/internalmessages/create_p_p_m_shipment.go index 4457e49a4bf..e98ad699dda 100644 --- a/pkg/gen/internalmessages/create_p_p_m_shipment.go +++ b/pkg/gen/internalmessages/create_p_p_m_shipment.go @@ -21,7 +21,7 @@ type CreatePPMShipment struct { // destination address // Required: true - DestinationAddress *Address `json:"destinationAddress"` + DestinationAddress *PPMDestinationAddress `json:"destinationAddress"` // Date the customer expects to move. // diff --git a/pkg/gen/internalmessages/p_p_m_destination_address.go b/pkg/gen/internalmessages/p_p_m_destination_address.go new file mode 100644 index 00000000000..db06a5d8c1d --- /dev/null +++ b/pkg/gen/internalmessages/p_p_m_destination_address.go @@ -0,0 +1,358 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package internalmessages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// PPMDestinationAddress A postal address +// +// swagger:model PPMDestinationAddress +type PPMDestinationAddress struct { + + // City + // Example: Anytown + // Required: true + City *string `json:"city"` + + // Country + // Example: USA + Country *string `json:"country,omitempty"` + + // County + // Example: LOS ANGELES + County *string `json:"county,omitempty"` + + // e tag + // Read Only: true + ETag string `json:"eTag,omitempty"` + + // id + // Example: c56a4180-65aa-42ec-a945-5fd21dec0538 + // Format: uuid + ID strfmt.UUID `json:"id,omitempty"` + + // ZIP + // Example: 90210 + // Required: true + // Pattern: ^(\d{5}([\-]\d{4})?)$ + PostalCode *string `json:"postalCode"` + + // State + // Required: true + // Enum: [AL AK AR AZ CA CO CT DC DE FL GA HI IA ID IL IN KS KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY] + State *string `json:"state"` + + // Street address 1 + // Example: 123 Main Ave + StreetAddress1 *string `json:"streetAddress1,omitempty"` + + // Street address 2 + // Example: Apartment 9000 + StreetAddress2 *string `json:"streetAddress2,omitempty"` + + // Address Line 3 + // Example: Montmârtre + StreetAddress3 *string `json:"streetAddress3,omitempty"` +} + +// Validate validates this p p m destination address +func (m *PPMDestinationAddress) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCity(formats); err != nil { + res = append(res, err) + } + + if err := m.validateID(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePostalCode(formats); err != nil { + res = append(res, err) + } + + if err := m.validateState(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PPMDestinationAddress) validateCity(formats strfmt.Registry) error { + + if err := validate.Required("city", "body", m.City); err != nil { + return err + } + + return nil +} + +func (m *PPMDestinationAddress) validateID(formats strfmt.Registry) error { + if swag.IsZero(m.ID) { // not required + return nil + } + + if err := validate.FormatOf("id", "body", "uuid", m.ID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *PPMDestinationAddress) validatePostalCode(formats strfmt.Registry) error { + + if err := validate.Required("postalCode", "body", m.PostalCode); err != nil { + return err + } + + if err := validate.Pattern("postalCode", "body", *m.PostalCode, `^(\d{5}([\-]\d{4})?)$`); err != nil { + return err + } + + return nil +} + +var pPMDestinationAddressTypeStatePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["AL","AK","AR","AZ","CA","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL","IN","KS","KY","LA","MA","MD","ME","MI","MN","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VA","VT","WA","WI","WV","WY"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + pPMDestinationAddressTypeStatePropEnum = append(pPMDestinationAddressTypeStatePropEnum, v) + } +} + +const ( + + // PPMDestinationAddressStateAL captures enum value "AL" + PPMDestinationAddressStateAL string = "AL" + + // PPMDestinationAddressStateAK captures enum value "AK" + PPMDestinationAddressStateAK string = "AK" + + // PPMDestinationAddressStateAR captures enum value "AR" + PPMDestinationAddressStateAR string = "AR" + + // PPMDestinationAddressStateAZ captures enum value "AZ" + PPMDestinationAddressStateAZ string = "AZ" + + // PPMDestinationAddressStateCA captures enum value "CA" + PPMDestinationAddressStateCA string = "CA" + + // PPMDestinationAddressStateCO captures enum value "CO" + PPMDestinationAddressStateCO string = "CO" + + // PPMDestinationAddressStateCT captures enum value "CT" + PPMDestinationAddressStateCT string = "CT" + + // PPMDestinationAddressStateDC captures enum value "DC" + PPMDestinationAddressStateDC string = "DC" + + // PPMDestinationAddressStateDE captures enum value "DE" + PPMDestinationAddressStateDE string = "DE" + + // PPMDestinationAddressStateFL captures enum value "FL" + PPMDestinationAddressStateFL string = "FL" + + // PPMDestinationAddressStateGA captures enum value "GA" + PPMDestinationAddressStateGA string = "GA" + + // PPMDestinationAddressStateHI captures enum value "HI" + PPMDestinationAddressStateHI string = "HI" + + // PPMDestinationAddressStateIA captures enum value "IA" + PPMDestinationAddressStateIA string = "IA" + + // PPMDestinationAddressStateID captures enum value "ID" + PPMDestinationAddressStateID string = "ID" + + // PPMDestinationAddressStateIL captures enum value "IL" + PPMDestinationAddressStateIL string = "IL" + + // PPMDestinationAddressStateIN captures enum value "IN" + PPMDestinationAddressStateIN string = "IN" + + // PPMDestinationAddressStateKS captures enum value "KS" + PPMDestinationAddressStateKS string = "KS" + + // PPMDestinationAddressStateKY captures enum value "KY" + PPMDestinationAddressStateKY string = "KY" + + // PPMDestinationAddressStateLA captures enum value "LA" + PPMDestinationAddressStateLA string = "LA" + + // PPMDestinationAddressStateMA captures enum value "MA" + PPMDestinationAddressStateMA string = "MA" + + // PPMDestinationAddressStateMD captures enum value "MD" + PPMDestinationAddressStateMD string = "MD" + + // PPMDestinationAddressStateME captures enum value "ME" + PPMDestinationAddressStateME string = "ME" + + // PPMDestinationAddressStateMI captures enum value "MI" + PPMDestinationAddressStateMI string = "MI" + + // PPMDestinationAddressStateMN captures enum value "MN" + PPMDestinationAddressStateMN string = "MN" + + // PPMDestinationAddressStateMO captures enum value "MO" + PPMDestinationAddressStateMO string = "MO" + + // PPMDestinationAddressStateMS captures enum value "MS" + PPMDestinationAddressStateMS string = "MS" + + // PPMDestinationAddressStateMT captures enum value "MT" + PPMDestinationAddressStateMT string = "MT" + + // PPMDestinationAddressStateNC captures enum value "NC" + PPMDestinationAddressStateNC string = "NC" + + // PPMDestinationAddressStateND captures enum value "ND" + PPMDestinationAddressStateND string = "ND" + + // PPMDestinationAddressStateNE captures enum value "NE" + PPMDestinationAddressStateNE string = "NE" + + // PPMDestinationAddressStateNH captures enum value "NH" + PPMDestinationAddressStateNH string = "NH" + + // PPMDestinationAddressStateNJ captures enum value "NJ" + PPMDestinationAddressStateNJ string = "NJ" + + // PPMDestinationAddressStateNM captures enum value "NM" + PPMDestinationAddressStateNM string = "NM" + + // PPMDestinationAddressStateNV captures enum value "NV" + PPMDestinationAddressStateNV string = "NV" + + // PPMDestinationAddressStateNY captures enum value "NY" + PPMDestinationAddressStateNY string = "NY" + + // PPMDestinationAddressStateOH captures enum value "OH" + PPMDestinationAddressStateOH string = "OH" + + // PPMDestinationAddressStateOK captures enum value "OK" + PPMDestinationAddressStateOK string = "OK" + + // PPMDestinationAddressStateOR captures enum value "OR" + PPMDestinationAddressStateOR string = "OR" + + // PPMDestinationAddressStatePA captures enum value "PA" + PPMDestinationAddressStatePA string = "PA" + + // PPMDestinationAddressStateRI captures enum value "RI" + PPMDestinationAddressStateRI string = "RI" + + // PPMDestinationAddressStateSC captures enum value "SC" + PPMDestinationAddressStateSC string = "SC" + + // PPMDestinationAddressStateSD captures enum value "SD" + PPMDestinationAddressStateSD string = "SD" + + // PPMDestinationAddressStateTN captures enum value "TN" + PPMDestinationAddressStateTN string = "TN" + + // PPMDestinationAddressStateTX captures enum value "TX" + PPMDestinationAddressStateTX string = "TX" + + // PPMDestinationAddressStateUT captures enum value "UT" + PPMDestinationAddressStateUT string = "UT" + + // PPMDestinationAddressStateVA captures enum value "VA" + PPMDestinationAddressStateVA string = "VA" + + // PPMDestinationAddressStateVT captures enum value "VT" + PPMDestinationAddressStateVT string = "VT" + + // PPMDestinationAddressStateWA captures enum value "WA" + PPMDestinationAddressStateWA string = "WA" + + // PPMDestinationAddressStateWI captures enum value "WI" + PPMDestinationAddressStateWI string = "WI" + + // PPMDestinationAddressStateWV captures enum value "WV" + PPMDestinationAddressStateWV string = "WV" + + // PPMDestinationAddressStateWY captures enum value "WY" + PPMDestinationAddressStateWY string = "WY" +) + +// prop value enum +func (m *PPMDestinationAddress) validateStateEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, pPMDestinationAddressTypeStatePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *PPMDestinationAddress) validateState(formats strfmt.Registry) error { + + if err := validate.Required("state", "body", m.State); err != nil { + return err + } + + // value enum + if err := m.validateStateEnum("state", "body", *m.State); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this p p m destination address based on the context it is used +func (m *PPMDestinationAddress) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateETag(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PPMDestinationAddress) contextValidateETag(ctx context.Context, formats strfmt.Registry) error { + + if err := validate.ReadOnly(ctx, "eTag", "body", string(m.ETag)); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PPMDestinationAddress) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PPMDestinationAddress) UnmarshalBinary(b []byte) error { + var res PPMDestinationAddress + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/gen/internalmessages/update_p_p_m_shipment.go b/pkg/gen/internalmessages/update_p_p_m_shipment.go index b37d87bf531..f6c344e863a 100644 --- a/pkg/gen/internalmessages/update_p_p_m_shipment.go +++ b/pkg/gen/internalmessages/update_p_p_m_shipment.go @@ -48,7 +48,7 @@ type UpdatePPMShipment struct { AdvanceAmountRequested *int64 `json:"advanceAmountRequested,omitempty"` // destination address - DestinationAddress *Address `json:"destinationAddress,omitempty"` + DestinationAddress *PPMDestinationAddress `json:"destinationAddress,omitempty"` // estimated weight // Example: 4200 diff --git a/pkg/gen/primev3api/embedded_spec.go b/pkg/gen/primev3api/embedded_spec.go index 199794b1ccd..2900f847d8d 100644 --- a/pkg/gen/primev3api/embedded_spec.go +++ b/pkg/gen/primev3api/embedded_spec.go @@ -831,7 +831,7 @@ func init() { "description": "The address of the destination location where goods are being delivered to.", "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, @@ -2138,6 +2138,179 @@ func init() { "WOUNDED_WARRIOR": "Wounded Warrior" } }, + "PPMDestinationAddress": { + "description": "A postal address", + "type": "object", + "required": [ + "city", + "state", + "postalCode" + ], + "properties": { + "city": { + "type": "string", + "title": "City", + "example": "Anytown" + }, + "country": { + "type": "string", + "title": "Country", + "default": "USA", + "x-nullable": true, + "example": "USA" + }, + "county": { + "type": "string", + "title": "County", + "x-nullable": true, + "example": "LOS ANGELES" + }, + "eTag": { + "type": "string", + "readOnly": true + }, + "id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, + "postalCode": { + "type": "string", + "format": "zip", + "title": "ZIP", + "pattern": "^(\\d{5}([\\-]\\d{4})?)$", + "example": "90210" + }, + "state": { + "type": "string", + "title": "State", + "enum": [ + "AL", + "AK", + "AR", + "AZ", + "CA", + "CO", + "CT", + "DC", + "DE", + "FL", + "GA", + "HI", + "IA", + "ID", + "IL", + "IN", + "KS", + "KY", + "LA", + "MA", + "MD", + "ME", + "MI", + "MN", + "MO", + "MS", + "MT", + "NC", + "ND", + "NE", + "NH", + "NJ", + "NM", + "NV", + "NY", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VA", + "VT", + "WA", + "WI", + "WV", + "WY" + ], + "x-display-value": { + "AK": "AK", + "AL": "AL", + "AR": "AR", + "AZ": "AZ", + "CA": "CA", + "CO": "CO", + "CT": "CT", + "DC": "DC", + "DE": "DE", + "FL": "FL", + "GA": "GA", + "HI": "HI", + "IA": "IA", + "ID": "ID", + "IL": "IL", + "IN": "IN", + "KS": "KS", + "KY": "KY", + "LA": "LA", + "MA": "MA", + "MD": "MD", + "ME": "ME", + "MI": "MI", + "MN": "MN", + "MO": "MO", + "MS": "MS", + "MT": "MT", + "NC": "NC", + "ND": "ND", + "NE": "NE", + "NH": "NH", + "NJ": "NJ", + "NM": "NM", + "NV": "NV", + "NY": "NY", + "OH": "OH", + "OK": "OK", + "OR": "OR", + "PA": "PA", + "RI": "RI", + "SC": "SC", + "SD": "SD", + "TN": "TN", + "TX": "TX", + "UT": "UT", + "VA": "VA", + "VT": "VT", + "WA": "WA", + "WI": "WI", + "WV": "WV", + "WY": "WY" + } + }, + "streetAddress1": { + "type": "string", + "title": "Street address 1", + "x-nullable": true, + "example": "123 Main Ave" + }, + "streetAddress2": { + "type": "string", + "title": "Street address 2", + "x-nullable": true, + "example": "Apartment 9000" + }, + "streetAddress3": { + "type": "string", + "title": "Address Line 3", + "x-nullable": true, + "example": "Montmârtre" + } + } + }, "PPMShipment": { "description": "A personally procured move is a type of shipment that a service member moves themselves.", "required": [ @@ -2207,7 +2380,7 @@ func init() { "readOnly": true }, "destinationAddress": { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" }, "eTag": { "description": "A hash unique to this shipment that should be used as the \"If-Match\" header for any updates.", @@ -3362,7 +3535,7 @@ func init() { "description": "The address of the destination location where goods are being delivered to.\n", "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, @@ -4538,7 +4711,7 @@ func init() { "description": "The address of the destination location where goods are being delivered to.", "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, @@ -5845,6 +6018,179 @@ func init() { "WOUNDED_WARRIOR": "Wounded Warrior" } }, + "PPMDestinationAddress": { + "description": "A postal address", + "type": "object", + "required": [ + "city", + "state", + "postalCode" + ], + "properties": { + "city": { + "type": "string", + "title": "City", + "example": "Anytown" + }, + "country": { + "type": "string", + "title": "Country", + "default": "USA", + "x-nullable": true, + "example": "USA" + }, + "county": { + "type": "string", + "title": "County", + "x-nullable": true, + "example": "LOS ANGELES" + }, + "eTag": { + "type": "string", + "readOnly": true + }, + "id": { + "type": "string", + "format": "uuid", + "example": "c56a4180-65aa-42ec-a945-5fd21dec0538" + }, + "postalCode": { + "type": "string", + "format": "zip", + "title": "ZIP", + "pattern": "^(\\d{5}([\\-]\\d{4})?)$", + "example": "90210" + }, + "state": { + "type": "string", + "title": "State", + "enum": [ + "AL", + "AK", + "AR", + "AZ", + "CA", + "CO", + "CT", + "DC", + "DE", + "FL", + "GA", + "HI", + "IA", + "ID", + "IL", + "IN", + "KS", + "KY", + "LA", + "MA", + "MD", + "ME", + "MI", + "MN", + "MO", + "MS", + "MT", + "NC", + "ND", + "NE", + "NH", + "NJ", + "NM", + "NV", + "NY", + "OH", + "OK", + "OR", + "PA", + "RI", + "SC", + "SD", + "TN", + "TX", + "UT", + "VA", + "VT", + "WA", + "WI", + "WV", + "WY" + ], + "x-display-value": { + "AK": "AK", + "AL": "AL", + "AR": "AR", + "AZ": "AZ", + "CA": "CA", + "CO": "CO", + "CT": "CT", + "DC": "DC", + "DE": "DE", + "FL": "FL", + "GA": "GA", + "HI": "HI", + "IA": "IA", + "ID": "ID", + "IL": "IL", + "IN": "IN", + "KS": "KS", + "KY": "KY", + "LA": "LA", + "MA": "MA", + "MD": "MD", + "ME": "ME", + "MI": "MI", + "MN": "MN", + "MO": "MO", + "MS": "MS", + "MT": "MT", + "NC": "NC", + "ND": "ND", + "NE": "NE", + "NH": "NH", + "NJ": "NJ", + "NM": "NM", + "NV": "NV", + "NY": "NY", + "OH": "OH", + "OK": "OK", + "OR": "OR", + "PA": "PA", + "RI": "RI", + "SC": "SC", + "SD": "SD", + "TN": "TN", + "TX": "TX", + "UT": "UT", + "VA": "VA", + "VT": "VT", + "WA": "WA", + "WI": "WI", + "WV": "WV", + "WY": "WY" + } + }, + "streetAddress1": { + "type": "string", + "title": "Street address 1", + "x-nullable": true, + "example": "123 Main Ave" + }, + "streetAddress2": { + "type": "string", + "title": "Street address 2", + "x-nullable": true, + "example": "Apartment 9000" + }, + "streetAddress3": { + "type": "string", + "title": "Address Line 3", + "x-nullable": true, + "example": "Montmârtre" + } + } + }, "PPMShipment": { "description": "A personally procured move is a type of shipment that a service member moves themselves.", "required": [ @@ -5914,7 +6260,7 @@ func init() { "readOnly": true }, "destinationAddress": { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" }, "eTag": { "description": "A hash unique to this shipment that should be used as the \"If-Match\" header for any updates.", @@ -7071,7 +7417,7 @@ func init() { "description": "The address of the destination location where goods are being delivered to.\n", "allOf": [ { - "$ref": "#/definitions/Address" + "$ref": "#/definitions/PPMDestinationAddress" } ] }, diff --git a/pkg/gen/primev3messages/create_p_p_m_shipment.go b/pkg/gen/primev3messages/create_p_p_m_shipment.go index 1257b32198a..4a5f64b42f1 100644 --- a/pkg/gen/primev3messages/create_p_p_m_shipment.go +++ b/pkg/gen/primev3messages/create_p_p_m_shipment.go @@ -22,7 +22,7 @@ type CreatePPMShipment struct { // The address of the destination location where goods are being delivered to. // Required: true DestinationAddress struct { - Address + PPMDestinationAddress } `json:"destinationAddress"` // The estimated weight of the PPM shipment goods being moved in pounds. diff --git a/pkg/gen/primev3messages/p_p_m_destination_address.go b/pkg/gen/primev3messages/p_p_m_destination_address.go new file mode 100644 index 00000000000..e6ac642a3f7 --- /dev/null +++ b/pkg/gen/primev3messages/p_p_m_destination_address.go @@ -0,0 +1,358 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package primev3messages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// PPMDestinationAddress A postal address +// +// swagger:model PPMDestinationAddress +type PPMDestinationAddress struct { + + // City + // Example: Anytown + // Required: true + City *string `json:"city"` + + // Country + // Example: USA + Country *string `json:"country,omitempty"` + + // County + // Example: LOS ANGELES + County *string `json:"county,omitempty"` + + // e tag + // Read Only: true + ETag string `json:"eTag,omitempty"` + + // id + // Example: c56a4180-65aa-42ec-a945-5fd21dec0538 + // Format: uuid + ID strfmt.UUID `json:"id,omitempty"` + + // ZIP + // Example: 90210 + // Required: true + // Pattern: ^(\d{5}([\-]\d{4})?)$ + PostalCode *string `json:"postalCode"` + + // State + // Required: true + // Enum: [AL AK AR AZ CA CO CT DC DE FL GA HI IA ID IL IN KS KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY] + State *string `json:"state"` + + // Street address 1 + // Example: 123 Main Ave + StreetAddress1 *string `json:"streetAddress1,omitempty"` + + // Street address 2 + // Example: Apartment 9000 + StreetAddress2 *string `json:"streetAddress2,omitempty"` + + // Address Line 3 + // Example: Montmârtre + StreetAddress3 *string `json:"streetAddress3,omitempty"` +} + +// Validate validates this p p m destination address +func (m *PPMDestinationAddress) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCity(formats); err != nil { + res = append(res, err) + } + + if err := m.validateID(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePostalCode(formats); err != nil { + res = append(res, err) + } + + if err := m.validateState(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PPMDestinationAddress) validateCity(formats strfmt.Registry) error { + + if err := validate.Required("city", "body", m.City); err != nil { + return err + } + + return nil +} + +func (m *PPMDestinationAddress) validateID(formats strfmt.Registry) error { + if swag.IsZero(m.ID) { // not required + return nil + } + + if err := validate.FormatOf("id", "body", "uuid", m.ID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *PPMDestinationAddress) validatePostalCode(formats strfmt.Registry) error { + + if err := validate.Required("postalCode", "body", m.PostalCode); err != nil { + return err + } + + if err := validate.Pattern("postalCode", "body", *m.PostalCode, `^(\d{5}([\-]\d{4})?)$`); err != nil { + return err + } + + return nil +} + +var pPMDestinationAddressTypeStatePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["AL","AK","AR","AZ","CA","CO","CT","DC","DE","FL","GA","HI","IA","ID","IL","IN","KS","KY","LA","MA","MD","ME","MI","MN","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VA","VT","WA","WI","WV","WY"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + pPMDestinationAddressTypeStatePropEnum = append(pPMDestinationAddressTypeStatePropEnum, v) + } +} + +const ( + + // PPMDestinationAddressStateAL captures enum value "AL" + PPMDestinationAddressStateAL string = "AL" + + // PPMDestinationAddressStateAK captures enum value "AK" + PPMDestinationAddressStateAK string = "AK" + + // PPMDestinationAddressStateAR captures enum value "AR" + PPMDestinationAddressStateAR string = "AR" + + // PPMDestinationAddressStateAZ captures enum value "AZ" + PPMDestinationAddressStateAZ string = "AZ" + + // PPMDestinationAddressStateCA captures enum value "CA" + PPMDestinationAddressStateCA string = "CA" + + // PPMDestinationAddressStateCO captures enum value "CO" + PPMDestinationAddressStateCO string = "CO" + + // PPMDestinationAddressStateCT captures enum value "CT" + PPMDestinationAddressStateCT string = "CT" + + // PPMDestinationAddressStateDC captures enum value "DC" + PPMDestinationAddressStateDC string = "DC" + + // PPMDestinationAddressStateDE captures enum value "DE" + PPMDestinationAddressStateDE string = "DE" + + // PPMDestinationAddressStateFL captures enum value "FL" + PPMDestinationAddressStateFL string = "FL" + + // PPMDestinationAddressStateGA captures enum value "GA" + PPMDestinationAddressStateGA string = "GA" + + // PPMDestinationAddressStateHI captures enum value "HI" + PPMDestinationAddressStateHI string = "HI" + + // PPMDestinationAddressStateIA captures enum value "IA" + PPMDestinationAddressStateIA string = "IA" + + // PPMDestinationAddressStateID captures enum value "ID" + PPMDestinationAddressStateID string = "ID" + + // PPMDestinationAddressStateIL captures enum value "IL" + PPMDestinationAddressStateIL string = "IL" + + // PPMDestinationAddressStateIN captures enum value "IN" + PPMDestinationAddressStateIN string = "IN" + + // PPMDestinationAddressStateKS captures enum value "KS" + PPMDestinationAddressStateKS string = "KS" + + // PPMDestinationAddressStateKY captures enum value "KY" + PPMDestinationAddressStateKY string = "KY" + + // PPMDestinationAddressStateLA captures enum value "LA" + PPMDestinationAddressStateLA string = "LA" + + // PPMDestinationAddressStateMA captures enum value "MA" + PPMDestinationAddressStateMA string = "MA" + + // PPMDestinationAddressStateMD captures enum value "MD" + PPMDestinationAddressStateMD string = "MD" + + // PPMDestinationAddressStateME captures enum value "ME" + PPMDestinationAddressStateME string = "ME" + + // PPMDestinationAddressStateMI captures enum value "MI" + PPMDestinationAddressStateMI string = "MI" + + // PPMDestinationAddressStateMN captures enum value "MN" + PPMDestinationAddressStateMN string = "MN" + + // PPMDestinationAddressStateMO captures enum value "MO" + PPMDestinationAddressStateMO string = "MO" + + // PPMDestinationAddressStateMS captures enum value "MS" + PPMDestinationAddressStateMS string = "MS" + + // PPMDestinationAddressStateMT captures enum value "MT" + PPMDestinationAddressStateMT string = "MT" + + // PPMDestinationAddressStateNC captures enum value "NC" + PPMDestinationAddressStateNC string = "NC" + + // PPMDestinationAddressStateND captures enum value "ND" + PPMDestinationAddressStateND string = "ND" + + // PPMDestinationAddressStateNE captures enum value "NE" + PPMDestinationAddressStateNE string = "NE" + + // PPMDestinationAddressStateNH captures enum value "NH" + PPMDestinationAddressStateNH string = "NH" + + // PPMDestinationAddressStateNJ captures enum value "NJ" + PPMDestinationAddressStateNJ string = "NJ" + + // PPMDestinationAddressStateNM captures enum value "NM" + PPMDestinationAddressStateNM string = "NM" + + // PPMDestinationAddressStateNV captures enum value "NV" + PPMDestinationAddressStateNV string = "NV" + + // PPMDestinationAddressStateNY captures enum value "NY" + PPMDestinationAddressStateNY string = "NY" + + // PPMDestinationAddressStateOH captures enum value "OH" + PPMDestinationAddressStateOH string = "OH" + + // PPMDestinationAddressStateOK captures enum value "OK" + PPMDestinationAddressStateOK string = "OK" + + // PPMDestinationAddressStateOR captures enum value "OR" + PPMDestinationAddressStateOR string = "OR" + + // PPMDestinationAddressStatePA captures enum value "PA" + PPMDestinationAddressStatePA string = "PA" + + // PPMDestinationAddressStateRI captures enum value "RI" + PPMDestinationAddressStateRI string = "RI" + + // PPMDestinationAddressStateSC captures enum value "SC" + PPMDestinationAddressStateSC string = "SC" + + // PPMDestinationAddressStateSD captures enum value "SD" + PPMDestinationAddressStateSD string = "SD" + + // PPMDestinationAddressStateTN captures enum value "TN" + PPMDestinationAddressStateTN string = "TN" + + // PPMDestinationAddressStateTX captures enum value "TX" + PPMDestinationAddressStateTX string = "TX" + + // PPMDestinationAddressStateUT captures enum value "UT" + PPMDestinationAddressStateUT string = "UT" + + // PPMDestinationAddressStateVA captures enum value "VA" + PPMDestinationAddressStateVA string = "VA" + + // PPMDestinationAddressStateVT captures enum value "VT" + PPMDestinationAddressStateVT string = "VT" + + // PPMDestinationAddressStateWA captures enum value "WA" + PPMDestinationAddressStateWA string = "WA" + + // PPMDestinationAddressStateWI captures enum value "WI" + PPMDestinationAddressStateWI string = "WI" + + // PPMDestinationAddressStateWV captures enum value "WV" + PPMDestinationAddressStateWV string = "WV" + + // PPMDestinationAddressStateWY captures enum value "WY" + PPMDestinationAddressStateWY string = "WY" +) + +// prop value enum +func (m *PPMDestinationAddress) validateStateEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, pPMDestinationAddressTypeStatePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *PPMDestinationAddress) validateState(formats strfmt.Registry) error { + + if err := validate.Required("state", "body", m.State); err != nil { + return err + } + + // value enum + if err := m.validateStateEnum("state", "body", *m.State); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this p p m destination address based on the context it is used +func (m *PPMDestinationAddress) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateETag(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PPMDestinationAddress) contextValidateETag(ctx context.Context, formats strfmt.Registry) error { + + if err := validate.ReadOnly(ctx, "eTag", "body", string(m.ETag)); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PPMDestinationAddress) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PPMDestinationAddress) UnmarshalBinary(b []byte) error { + var res PPMDestinationAddress + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/gen/primev3messages/p_p_m_shipment.go b/pkg/gen/primev3messages/p_p_m_shipment.go index 99a834a1303..d2636b3a673 100644 --- a/pkg/gen/primev3messages/p_p_m_shipment.go +++ b/pkg/gen/primev3messages/p_p_m_shipment.go @@ -59,7 +59,7 @@ type PPMShipment struct { // destination address // Required: true - DestinationAddress *Address `json:"destinationAddress"` + DestinationAddress *PPMDestinationAddress `json:"destinationAddress"` // A hash unique to this shipment that should be used as the "If-Match" header for any updates. // Required: true diff --git a/pkg/gen/primev3messages/update_p_p_m_shipment.go b/pkg/gen/primev3messages/update_p_p_m_shipment.go index ead98493601..fee38e21a8d 100644 --- a/pkg/gen/primev3messages/update_p_p_m_shipment.go +++ b/pkg/gen/primev3messages/update_p_p_m_shipment.go @@ -22,7 +22,7 @@ type UpdatePPMShipment struct { // The address of the destination location where goods are being delivered to. // DestinationAddress struct { - Address + PPMDestinationAddress } `json:"destinationAddress,omitempty"` // The estimated weight of the PPM shipment goods being moved. diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go index f8b68b93df4..b761ed13604 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "math" + "strings" "time" "github.com/go-openapi/strfmt" @@ -736,6 +737,23 @@ func Address(address *models.Address) *ghcmessages.Address { } } +// PPM destination Address payload +func PPMDestinationAddress(address *models.Address) *ghcmessages.Address { + payload := Address(address) + + if payload == nil { + return nil + } + + // Street address 1 is optional per business rule but not nullable on the database level. + // Check if streetAddress 1 is using place holder value to represent 'NULL'. + // If so return empty string. + if strings.EqualFold(*payload.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) { + payload.StreetAddress1 = models.StringPointer("") + } + return payload +} + // StorageFacility payload func StorageFacility(storageFacility *models.StorageFacility) *ghcmessages.StorageFacility { if storageFacility == nil { @@ -888,7 +906,7 @@ func PPMShipment(_ storage.FileStorer, ppmShipment *models.PPMShipment) *ghcmess ReviewedAt: handlers.FmtDateTimePtr(ppmShipment.ReviewedAt), ApprovedAt: handlers.FmtDateTimePtr(ppmShipment.ApprovedAt), PickupAddress: Address(ppmShipment.PickupAddress), - DestinationAddress: Address(ppmShipment.DestinationAddress), + DestinationAddress: PPMDestinationAddress(ppmShipment.DestinationAddress), ActualPickupPostalCode: ppmShipment.ActualPickupPostalCode, ActualDestinationPostalCode: ppmShipment.ActualDestinationPostalCode, SitExpected: ppmShipment.SITExpected, diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go index 34dc9c5b2db..73eb7e5b6a6 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go @@ -78,7 +78,44 @@ func (suite *PayloadsSuite) TestFetchPPMShipment() { suite.Equal(&state, returnedPPMShipment.DestinationAddress.State) suite.Equal(&country.Country, returnedPPMShipment.DestinationAddress.Country) suite.Equal(&county, returnedPPMShipment.DestinationAddress.County) + }) + + suite.Run("Destination street address 1 returns empty string to convey OPTIONAL state ", func() { + expected_street_address_1 := "" + expectedAddress2 := models.Address{ + StreetAddress1: expected_street_address_1, + StreetAddress2: &streetAddress2, + StreetAddress3: &streetAddress3, + City: city, + State: state, + PostalCode: postalcode, + Country: &country, + County: county, + } + + expectedPPMShipment2 := models.PPMShipment{ + ID: ppmShipmentID, + PickupAddress: &expectedAddress, + DestinationAddress: &expectedAddress2, + } + returnedPPMShipment := PPMShipment(nil, &expectedPPMShipment2) + suite.IsType(returnedPPMShipment, &ghcmessages.PPMShipment{}) + suite.Equal(&streetAddress1, returnedPPMShipment.PickupAddress.StreetAddress1) + suite.Equal(expectedPPMShipment.PickupAddress.StreetAddress2, returnedPPMShipment.PickupAddress.StreetAddress2) + suite.Equal(expectedPPMShipment.PickupAddress.StreetAddress3, returnedPPMShipment.PickupAddress.StreetAddress3) + suite.Equal(&postalcode, returnedPPMShipment.PickupAddress.PostalCode) + suite.Equal(&city, returnedPPMShipment.PickupAddress.City) + suite.Equal(&state, returnedPPMShipment.PickupAddress.State) + suite.Equal(&county, returnedPPMShipment.PickupAddress.County) + + suite.Equal(&expected_street_address_1, returnedPPMShipment.DestinationAddress.StreetAddress1) + suite.Equal(expectedPPMShipment.DestinationAddress.StreetAddress2, returnedPPMShipment.DestinationAddress.StreetAddress2) + suite.Equal(expectedPPMShipment.DestinationAddress.StreetAddress3, returnedPPMShipment.DestinationAddress.StreetAddress3) + suite.Equal(&postalcode, returnedPPMShipment.DestinationAddress.PostalCode) + suite.Equal(&city, returnedPPMShipment.DestinationAddress.City) + suite.Equal(&state, returnedPPMShipment.DestinationAddress.State) + suite.Equal(&county, returnedPPMShipment.DestinationAddress.County) }) } diff --git a/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go b/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go index cd838e6a1bc..adafc0cb278 100644 --- a/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go +++ b/pkg/handlers/ghcapi/internal/payloads/payload_to_model.go @@ -2,6 +2,7 @@ package payloads import ( "errors" + "strings" "time" "github.com/go-openapi/strfmt" @@ -111,6 +112,44 @@ func AddressModel(address *ghcmessages.Address) *models.Address { return modelAddress } +// AddressModel model +func PPMDestinationAddressModel(address *ghcmessages.PPMDestinationAddress) *models.Address { + // To check if the model is intended to be blank, we'll look at ID and City, State, PostalCode + // We should always have ID if the user intends to update an Address, + // and City, State, PostalCode is a required field on creation. If both are blank, it should be treated as nil. + var blankSwaggerID strfmt.UUID + // unlike other addresses PPM destination address can be created without StreetAddress1 + if address == nil || (address.ID == blankSwaggerID && address.City == nil && address.State == nil && address.PostalCode == nil) { + return nil + } + + modelAddress := &models.Address{ + ID: uuid.FromStringOrNil(address.ID.String()), + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + if address.StreetAddress1 != nil && len(strings.Trim(*address.StreetAddress1, " ")) > 0 { + modelAddress.StreetAddress1 = *address.StreetAddress1 + } else { + // Street address 1 is optional for certain business context but not nullable on the database level. + // Use place holder text to represent NULL. + modelAddress.StreetAddress1 = models.STREET_ADDRESS_1_NOT_PROVIDED + } + + if address.City != nil { + modelAddress.City = *address.City + } + if address.State != nil { + modelAddress.State = *address.State + } + if address.PostalCode != nil { + modelAddress.PostalCode = *address.PostalCode + } + + return modelAddress +} + // StorageFacilityModel model func StorageFacilityModel(storageFacility *ghcmessages.StorageFacility) *models.StorageFacility { // To check if the model is intended to be blank, we'll look at both ID and FacilityName @@ -307,7 +346,7 @@ func PPMShipmentModelFromCreate(ppmShipment *ghcmessages.CreatePPMShipment) *mod model.HasTertiaryPickupAddress = handlers.FmtBool(true) } - addressModel = AddressModel(&ppmShipment.DestinationAddress.Address) + addressModel = PPMDestinationAddressModel(&ppmShipment.DestinationAddress.PPMDestinationAddress) if addressModel != nil { model.DestinationAddress = addressModel } @@ -623,7 +662,7 @@ func PPMShipmentModelFromUpdate(ppmShipment *ghcmessages.UpdatePPMShipment) *mod model.TertiaryPickupAddressID = &tertiaryPickupAddressID } - addressModel = AddressModel(&ppmShipment.DestinationAddress.Address) + addressModel = PPMDestinationAddressModel(&ppmShipment.DestinationAddress.PPMDestinationAddress) if addressModel != nil { model.DestinationAddress = addressModel } diff --git a/pkg/handlers/ghcapi/internal/payloads/payload_to_model_test.go b/pkg/handlers/ghcapi/internal/payloads/payload_to_model_test.go new file mode 100644 index 00000000000..4919c613b65 --- /dev/null +++ b/pkg/handlers/ghcapi/internal/payloads/payload_to_model_test.go @@ -0,0 +1,155 @@ +package payloads + +import ( + "time" + + "github.com/transcom/mymove/pkg/gen/ghcmessages" + "github.com/transcom/mymove/pkg/handlers" + "github.com/transcom/mymove/pkg/models" +) + +func (suite *PayloadsSuite) TestPPMShipmentModelWithOptionalDestinationStreet1FromCreate() { + time := time.Now() + expectedDepartureDate := handlers.FmtDatePtr(&time) + + address := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "state", + PostalCode: "12345", + } + + var pickupAddress ghcmessages.Address + var destinationAddress ghcmessages.PPMDestinationAddress + + pickupAddress = ghcmessages.Address{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + destinationAddress = ghcmessages.PPMDestinationAddress{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: models.StringPointer(""), // empty string + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + ppmShipment := ghcmessages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + } + + model := PPMShipmentModelFromCreate(&ppmShipment) + + suite.NotNil(model) + suite.Equal(models.PPMShipmentStatusSubmitted, model.Status) + suite.Equal(model.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + suite.NotNil(model) + + // test when street address 1 contains white spaces + destinationAddress.StreetAddress1 = models.StringPointer(" ") + ppmShipmentWhiteSpaces := ghcmessages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + } + + model2 := PPMShipmentModelFromCreate(&ppmShipmentWhiteSpaces) + suite.Equal(model2.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test with valid street address 1 + streetAddress1 := "123 Street" + destinationAddress.StreetAddress1 = models.StringPointer(streetAddress1) + ppmShipmentRealDestinatonAddr1 := ghcmessages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + } + + model3 := PPMShipmentModelFromCreate(&ppmShipmentRealDestinatonAddr1) + suite.Equal(model3.DestinationAddress.StreetAddress1, streetAddress1) +} + +func (suite *PayloadsSuite) TestPPMShipmentModelWithOptionalDestinationStreet1FromUpdate() { + time := time.Now() + expectedDepartureDate := handlers.FmtDatePtr(&time) + + address := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "state", + PostalCode: "12345", + } + + var pickupAddress ghcmessages.Address + var destinationAddress ghcmessages.PPMDestinationAddress + + pickupAddress = ghcmessages.Address{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + destinationAddress = ghcmessages.PPMDestinationAddress{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: models.StringPointer(""), // empty string + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + ppmShipment := ghcmessages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + } + + model := PPMShipmentModelFromUpdate(&ppmShipment) + + suite.NotNil(model) + suite.Equal(model.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test when street address 1 contains white spaces + destinationAddress.StreetAddress1 = models.StringPointer(" ") + ppmShipmentWhiteSpaces := ghcmessages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + } + + model2 := PPMShipmentModelFromUpdate(&ppmShipmentWhiteSpaces) + suite.Equal(model2.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test with valid street address 1 + streetAddress1 := "123 Street" + destinationAddress.StreetAddress1 = models.StringPointer(streetAddress1) + ppmShipmentRealDestinatonAddr1 := ghcmessages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + } + + model3 := PPMShipmentModelFromUpdate(&ppmShipmentRealDestinatonAddr1) + suite.Equal(model3.DestinationAddress.StreetAddress1, streetAddress1) +} diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index 89e2008ced9..aa96acd49f0 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -3507,7 +3507,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { var pickupAddress ghcmessages.Address var secondaryPickupAddress ghcmessages.Address - var destinationAddress ghcmessages.Address + var destinationAddress ghcmessages.PPMDestinationAddress var secondaryDestinationAddress ghcmessages.Address expectedPickupAddress := factory.BuildAddress(nil, []factory.Customization{ @@ -3549,7 +3549,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { }, }, }, nil) - destinationAddress = ghcmessages.Address{ + destinationAddress = ghcmessages.PPMDestinationAddress{ City: &expectedDestinationAddress.City, PostalCode: &expectedDestinationAddress.PostalCode, State: &expectedDestinationAddress.State, @@ -3580,10 +3580,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: &shipmentType, PpmShipment: &ghcmessages.CreatePPMShipment{ - ExpectedDepartureDate: handlers.FmtDatePtr(expectedDepartureDate), - PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, - SecondaryPickupAddress: struct{ ghcmessages.Address }{secondaryPickupAddress}, - DestinationAddress: struct{ ghcmessages.Address }{destinationAddress}, + ExpectedDepartureDate: handlers.FmtDatePtr(expectedDepartureDate), + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + SecondaryPickupAddress: struct{ ghcmessages.Address }{secondaryPickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, SecondaryDestinationAddress: struct{ ghcmessages.Address }{secondaryDestinationAddress}, SitExpected: &sitExpected, SitLocation: &sitLocation, @@ -3698,7 +3700,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { estimatedIncentive := 123456 var pickupAddress ghcmessages.Address - var destinationAddress ghcmessages.Address + var destinationAddress ghcmessages.PPMDestinationAddress expectedPickupAddress := factory.BuildAddress(nil, []factory.Customization{ { @@ -3723,7 +3725,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { }, }, }, nil) - destinationAddress = ghcmessages.Address{ + destinationAddress = ghcmessages.PPMDestinationAddress{ City: &expectedDestinationAddress.City, PostalCode: &expectedDestinationAddress.PostalCode, State: &expectedDestinationAddress.State, @@ -3742,10 +3744,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { PpmShipment: &ghcmessages.CreatePPMShipment{ ExpectedDepartureDate: handlers.FmtDatePtr(expectedDepartureDate), PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, - DestinationAddress: struct{ ghcmessages.Address }{destinationAddress}, - SitExpected: &sitExpected, - EstimatedWeight: handlers.FmtPoundPtr(&estimatedWeight), - HasProGear: &hasProGear, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + SitExpected: &sitExpected, + EstimatedWeight: handlers.FmtPoundPtr(&estimatedWeight), + HasProGear: &hasProGear, }, }, } @@ -3840,7 +3844,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { estimatedIncentive := 123456 var pickupAddress ghcmessages.Address - var destinationAddress ghcmessages.Address + var destinationAddress ghcmessages.PPMDestinationAddress expectedPickupAddress := factory.BuildAddress(nil, []factory.Customization{ { @@ -3865,7 +3869,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { }, }, }, nil) - destinationAddress = ghcmessages.Address{ + destinationAddress = ghcmessages.PPMDestinationAddress{ City: &expectedDestinationAddress.City, PostalCode: &expectedDestinationAddress.PostalCode, State: &expectedDestinationAddress.State, @@ -3884,10 +3888,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { PpmShipment: &ghcmessages.CreatePPMShipment{ ExpectedDepartureDate: handlers.FmtDatePtr(expectedDepartureDate), PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, - DestinationAddress: struct{ ghcmessages.Address }{destinationAddress}, - SitExpected: &sitExpected, - EstimatedWeight: handlers.FmtPoundPtr(&estimatedWeight), - HasProGear: &hasProGear, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, + SitExpected: &sitExpected, + EstimatedWeight: handlers.FmtPoundPtr(&estimatedWeight), + HasProGear: &hasProGear, }, }, } @@ -4134,7 +4140,7 @@ func (suite *HandlerSuite) TestUpdateShipmentHandler() { var pickupAddress ghcmessages.Address var secondaryPickupAddress ghcmessages.Address - var destinationAddress ghcmessages.Address + var destinationAddress ghcmessages.PPMDestinationAddress var secondaryDestinationAddress ghcmessages.Address expectedPickupAddress := ppmShipment.PickupAddress @@ -4164,7 +4170,7 @@ func (suite *HandlerSuite) TestUpdateShipmentHandler() { } expectedDestinationAddress := ppmShipment.DestinationAddress - destinationAddress = ghcmessages.Address{ + destinationAddress = ghcmessages.PPMDestinationAddress{ City: &expectedDestinationAddress.City, PostalCode: &expectedDestinationAddress.PostalCode, State: &expectedDestinationAddress.State, @@ -4203,11 +4209,13 @@ func (suite *HandlerSuite) TestUpdateShipmentHandler() { params := suite.getUpdateShipmentParams(ppmShipment.Shipment) params.Body.ShipmentType = ghcmessages.MTOShipmentTypePPM params.Body.PpmShipment = &ghcmessages.UpdatePPMShipment{ - ActualMoveDate: handlers.FmtDatePtr(&actualMoveDate), - ExpectedDepartureDate: handlers.FmtDatePtr(&expectedDepartureDate), - PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, - SecondaryPickupAddress: struct{ ghcmessages.Address }{secondaryPickupAddress}, - DestinationAddress: struct{ ghcmessages.Address }{destinationAddress}, + ActualMoveDate: handlers.FmtDatePtr(&actualMoveDate), + ExpectedDepartureDate: handlers.FmtDatePtr(&expectedDepartureDate), + PickupAddress: struct{ ghcmessages.Address }{pickupAddress}, + SecondaryPickupAddress: struct{ ghcmessages.Address }{secondaryPickupAddress}, + DestinationAddress: struct { + ghcmessages.PPMDestinationAddress + }{destinationAddress}, SecondaryDestinationAddress: struct{ ghcmessages.Address }{secondaryDestinationAddress}, SitExpected: &sitExpected, SitEstimatedWeight: handlers.FmtPoundPtr(&sitEstimatedWeight), diff --git a/pkg/handlers/internalapi/internal/payloads/model_to_payload.go b/pkg/handlers/internalapi/internal/payloads/model_to_payload.go index e063c7db1cc..dd0fb960329 100644 --- a/pkg/handlers/internalapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/internalapi/internal/payloads/model_to_payload.go @@ -2,6 +2,7 @@ package payloads import ( "errors" + "strings" "github.com/go-openapi/strfmt" "github.com/gobuffalo/validate/v3" @@ -43,6 +44,23 @@ func Address(address *models.Address) *internalmessages.Address { } } +// PPM Destination Address payload +func PPMDestinationAddress(address *models.Address) *internalmessages.Address { + payload := Address(address) + + if payload == nil { + return nil + } + + // Street address 1 is optional per business rule but not nullable on the database level. + // Check if streetAddress 1 is using place holder value to represent 'NULL'. + // If so return empty string. + if strings.EqualFold(*payload.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) { + payload.StreetAddress1 = models.StringPointer("") + } + return payload +} + // MTOAgent payload func MTOAgent(mtoAgent *models.MTOAgent) *internalmessages.MTOAgent { if mtoAgent == nil { @@ -101,7 +119,7 @@ func PPMShipment(storer storage.FileStorer, ppmShipment *models.PPMShipment) *in TertiaryPickupAddress: Address(ppmShipment.TertiaryPickupAddress), HasTertiaryPickupAddress: ppmShipment.HasTertiaryPickupAddress, ActualPickupPostalCode: ppmShipment.ActualPickupPostalCode, - DestinationAddress: Address(ppmShipment.DestinationAddress), + DestinationAddress: PPMDestinationAddress(ppmShipment.DestinationAddress), SecondaryDestinationAddress: Address(ppmShipment.SecondaryDestinationAddress), HasSecondaryDestinationAddress: ppmShipment.HasSecondaryDestinationAddress, TertiaryDestinationAddress: Address(ppmShipment.TertiaryDestinationAddress), diff --git a/pkg/handlers/internalapi/internal/payloads/payload_to_model.go b/pkg/handlers/internalapi/internal/payloads/payload_to_model.go index 9a656eded1a..3c79075e600 100644 --- a/pkg/handlers/internalapi/internal/payloads/payload_to_model.go +++ b/pkg/handlers/internalapi/internal/payloads/payload_to_model.go @@ -1,6 +1,7 @@ package payloads import ( + "strings" "time" "github.com/go-openapi/strfmt" @@ -31,6 +32,32 @@ func AddressModel(address *internalmessages.Address) *models.Address { } } +func PPMDestinationAddressModel(address *internalmessages.PPMDestinationAddress) *models.Address { + if address == nil { + return nil + } + if address.County == nil { + address.County = models.StringPointer("") + } + addressModel := &models.Address{ + ID: uuid.FromStringOrNil(address.ID.String()), + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + City: *address.City, + State: *address.State, + PostalCode: *address.PostalCode, + County: *address.County, + } + if address.StreetAddress1 != nil && len(strings.Trim(*address.StreetAddress1, " ")) > 0 { + addressModel.StreetAddress1 = *address.StreetAddress1 + } else { + // Street address 1 is optional for certain business context but not nullable on the database level. + // Use place holder text to represent NULL. + addressModel.StreetAddress1 = models.STREET_ADDRESS_1_NOT_PROVIDED + } + return addressModel +} + // MTOAgentModel model func MTOAgentModel(mtoAgent *internalmessages.MTOAgent) *models.MTOAgent { if mtoAgent == nil { @@ -154,7 +181,7 @@ func PPMShipmentModelFromCreate(ppmShipment *internalmessages.CreatePPMShipment) } if ppmShipment.DestinationAddress != nil { - model.DestinationAddress = AddressModel(ppmShipment.DestinationAddress) + model.DestinationAddress = PPMDestinationAddressModel(ppmShipment.DestinationAddress) } model.HasSecondaryDestinationAddress = handlers.FmtBool(ppmShipment.SecondaryDestinationAddress != nil) @@ -213,7 +240,7 @@ func UpdatePPMShipmentModel(ppmShipment *internalmessages.UpdatePPMShipment) *mo } if ppmShipment.DestinationAddress != nil { - ppmModel.DestinationAddress = AddressModel(ppmShipment.DestinationAddress) + ppmModel.DestinationAddress = PPMDestinationAddressModel(ppmShipment.DestinationAddress) } if ppmShipment.SecondaryDestinationAddress != nil { diff --git a/pkg/handlers/internalapi/internal/payloads/payload_to_model_test.go b/pkg/handlers/internalapi/internal/payloads/payload_to_model_test.go new file mode 100644 index 00000000000..e6f49c8328e --- /dev/null +++ b/pkg/handlers/internalapi/internal/payloads/payload_to_model_test.go @@ -0,0 +1,141 @@ +package payloads + +import ( + "time" + + "github.com/transcom/mymove/pkg/gen/internalmessages" + "github.com/transcom/mymove/pkg/handlers" + "github.com/transcom/mymove/pkg/models" +) + +func (suite *PayloadsSuite) TestPPMShipmentModelWithOptionalDestinationStreet1FromCreate() { + time := time.Now() + expectedDepartureDate := handlers.FmtDatePtr(&time) + + address := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "state", + PostalCode: "12345", + } + + var pickupAddress internalmessages.Address + var destinationAddress internalmessages.PPMDestinationAddress + + pickupAddress = internalmessages.Address{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + destinationAddress = internalmessages.PPMDestinationAddress{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: models.StringPointer(""), // empty string + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + ppmShipment := internalmessages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, + } + + model := PPMShipmentModelFromCreate(&ppmShipment) + + suite.NotNil(model) + suite.Equal(model.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test when street address 1 contains white spaces + destinationAddress.StreetAddress1 = models.StringPointer(" ") + ppmShipmentWhiteSpaces := internalmessages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, + } + + model2 := PPMShipmentModelFromCreate(&ppmShipmentWhiteSpaces) + suite.Equal(model2.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test with valid street address 1 + streetAddress1 := "1234 Street" + destinationAddress.StreetAddress1 = &streetAddress1 + ppmShipmentValidDestAddress1 := internalmessages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, + } + + model3 := PPMShipmentModelFromCreate(&ppmShipmentValidDestAddress1) + suite.Equal(model3.DestinationAddress.StreetAddress1, streetAddress1) +} + +func (suite *PayloadsSuite) TestPPMShipmentModelWithOptionalDestinationStreet1FromUpdate() { + time := time.Now() + expectedDepartureDate := handlers.FmtDatePtr(&time) + + address := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "state", + PostalCode: "12345", + } + + var pickupAddress internalmessages.Address + var destinationAddress internalmessages.PPMDestinationAddress + + pickupAddress = internalmessages.Address{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + destinationAddress = internalmessages.PPMDestinationAddress{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: models.StringPointer(""), // empty string + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + ppmShipment := internalmessages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, + } + + model := UpdatePPMShipmentModel(&ppmShipment) + + suite.NotNil(model) + suite.Equal(model.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test when street address 1 contains white spaces + destinationAddress.StreetAddress1 = models.StringPointer(" ") + ppmShipmentWhiteSpaces := internalmessages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, + } + + model2 := UpdatePPMShipmentModel(&ppmShipmentWhiteSpaces) + suite.Equal(model2.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test with valid street address 1 + streetAddress1 := "1234 Street" + destinationAddress.StreetAddress1 = &streetAddress1 + ppmShipmentValidDestAddress1 := internalmessages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: &pickupAddress, + DestinationAddress: &destinationAddress, + } + + model3 := UpdatePPMShipmentModel(&ppmShipmentValidDestAddress1) + suite.Equal(model3.DestinationAddress.StreetAddress1, streetAddress1) +} diff --git a/pkg/handlers/internalapi/internal/payloads/payloads_test.go b/pkg/handlers/internalapi/internal/payloads/payloads_test.go new file mode 100644 index 00000000000..c17b8a85256 --- /dev/null +++ b/pkg/handlers/internalapi/internal/payloads/payloads_test.go @@ -0,0 +1,31 @@ +package payloads + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/transcom/mymove/pkg/handlers" + "github.com/transcom/mymove/pkg/notifications" + "github.com/transcom/mymove/pkg/storage" + storageTest "github.com/transcom/mymove/pkg/storage/test" + "github.com/transcom/mymove/pkg/testingsuite" +) + +// HandlerSuite is an abstraction of our original suite +type PayloadsSuite struct { + handlers.BaseHandlerTestSuite + storer storage.FileStorer +} + +// TestHandlerSuite creates our test suite +func TestHandlerSuite(t *testing.T) { + hs := &PayloadsSuite{ + BaseHandlerTestSuite: handlers.NewBaseHandlerTestSuite(notifications.NewStubNotificationSender("milmovelocal"), testingsuite.CurrentPackage(), + testingsuite.WithPerTestTransaction()), + storer: storageTest.NewFakeS3Storage(true), + } + + suite.Run(t, hs) + hs.PopTestSuite.TearDown() +} diff --git a/pkg/handlers/internalapi/mto_shipment_test.go b/pkg/handlers/internalapi/mto_shipment_test.go index 267cb24a323..f7245e1d3cb 100644 --- a/pkg/handlers/internalapi/mto_shipment_test.go +++ b/pkg/handlers/internalapi/mto_shipment_test.go @@ -271,7 +271,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerV1() { StreetAddress2: pickupAddress.StreetAddress2, StreetAddress3: pickupAddress.StreetAddress3, }, - DestinationAddress: &internalmessages.Address{ + DestinationAddress: &internalmessages.PPMDestinationAddress{ City: &destinationAddress.City, PostalCode: &destinationAddress.PostalCode, State: &destinationAddress.State, @@ -338,7 +338,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerV1() { StreetAddress2: pickupAddress.StreetAddress2, StreetAddress3: pickupAddress.StreetAddress3, }, - DestinationAddress: &internalmessages.Address{ + DestinationAddress: &internalmessages.PPMDestinationAddress{ City: &destinationAddress.City, PostalCode: &destinationAddress.PostalCode, State: &destinationAddress.State, diff --git a/pkg/handlers/primeapiv3/mto_shipment_test.go b/pkg/handlers/primeapiv3/mto_shipment_test.go index 21decb90c5a..4a90223e3cc 100644 --- a/pkg/handlers/primeapiv3/mto_shipment_test.go +++ b/pkg/handlers/primeapiv3/mto_shipment_test.go @@ -94,6 +94,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { var pickupAddress primev3messages.Address var secondaryPickupAddress primev3messages.Address var destinationAddress primev3messages.Address + var ppmDestinationAddress primev3messages.PPMDestinationAddress var secondaryDestinationAddress primev3messages.Address creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer()) @@ -257,6 +258,14 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { StreetAddress2: expectedDestinationAddress.StreetAddress2, StreetAddress3: expectedDestinationAddress.StreetAddress3, } + ppmDestinationAddress = primev3messages.PPMDestinationAddress{ + City: &expectedDestinationAddress.City, + PostalCode: &expectedDestinationAddress.PostalCode, + State: &expectedDestinationAddress.State, + StreetAddress1: &expectedDestinationAddress.StreetAddress1, + StreetAddress2: expectedDestinationAddress.StreetAddress2, + StreetAddress3: expectedDestinationAddress.StreetAddress3, + } expectedSecondaryDestinationAddress := address2 secondaryDestinationAddress = primev3messages.Address{ @@ -275,10 +284,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ShipmentType: primev3messages.NewMTOShipmentType(primev3messages.MTOShipmentTypePPM), CounselorRemarks: &counselorRemarks, PpmShipment: &primev3messages.CreatePPMShipment{ - ExpectedDepartureDate: handlers.FmtDate(expectedDepartureDate), - PickupAddress: struct{ primev3messages.Address }{pickupAddress}, - SecondaryPickupAddress: struct{ primev3messages.Address }{secondaryPickupAddress}, - DestinationAddress: struct{ primev3messages.Address }{destinationAddress}, + ExpectedDepartureDate: handlers.FmtDate(expectedDepartureDate), + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + SecondaryPickupAddress: struct{ primev3messages.Address }{secondaryPickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{ppmDestinationAddress}, SecondaryDestinationAddress: struct{ primev3messages.Address }{secondaryDestinationAddress}, SitExpected: &sitExpected, SitLocation: &sitLocation, @@ -427,6 +438,191 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { suite.False(*models.BoolPointer(*updatedPPM.HasSecondaryDestinationAddress)) }) + suite.Run("Successful POST/PATCH - Integration Test (PPM) - Destination address street 1 OPTIONAL", func() { + // Under Test: CreateMTOShipment handler code + // Setup: Create a PPM shipment on an available move + // Expected: Successful submission, status should be SUBMITTED + handler, move := setupTestData(true) + req := httptest.NewRequest("POST", "/mto-shipments", nil) + + counselorRemarks := "Some counselor remarks" + expectedDepartureDate := time.Now().AddDate(0, 0, 10) + sitExpected := true + sitLocation := primev3messages.SITLocationTypeDESTINATION + sitEstimatedWeight := unit.Pound(1500) + sitEstimatedEntryDate := expectedDepartureDate.AddDate(0, 0, 5) + sitEstimatedDepartureDate := sitEstimatedEntryDate.AddDate(0, 0, 20) + estimatedWeight := unit.Pound(3200) + hasProGear := true + proGearWeight := unit.Pound(400) + spouseProGearWeight := unit.Pound(250) + estimatedIncentive := 123456 + sitEstimatedCost := 67500 + + address1 := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "CA", + PostalCode: "90210", + } + addressWithEmptyStreet1 := models.Address{ + StreetAddress1: "", + City: "city", + State: "CA", + PostalCode: "90210", + } + + expectedPickupAddress := address1 + pickupAddress = primev3messages.Address{ + City: &expectedPickupAddress.City, + PostalCode: &expectedPickupAddress.PostalCode, + State: &expectedPickupAddress.State, + StreetAddress1: &expectedPickupAddress.StreetAddress1, + StreetAddress2: expectedPickupAddress.StreetAddress2, + StreetAddress3: expectedPickupAddress.StreetAddress3, + } + + expectedDestinationAddress := address1 + destinationAddress = primev3messages.Address{ + City: &expectedDestinationAddress.City, + PostalCode: &expectedDestinationAddress.PostalCode, + State: &expectedDestinationAddress.State, + StreetAddress1: &expectedDestinationAddress.StreetAddress1, + StreetAddress2: expectedDestinationAddress.StreetAddress2, + StreetAddress3: expectedDestinationAddress.StreetAddress3, + } + ppmDestinationAddress = primev3messages.PPMDestinationAddress{ + City: &addressWithEmptyStreet1.City, + PostalCode: &addressWithEmptyStreet1.PostalCode, + State: &addressWithEmptyStreet1.State, + StreetAddress1: &addressWithEmptyStreet1.StreetAddress1, + StreetAddress2: addressWithEmptyStreet1.StreetAddress2, + StreetAddress3: addressWithEmptyStreet1.StreetAddress3, + } + + params := mtoshipmentops.CreateMTOShipmentParams{ + HTTPRequest: req, + Body: &primev3messages.CreateMTOShipment{ + MoveTaskOrderID: handlers.FmtUUID(move.ID), + ShipmentType: primev3messages.NewMTOShipmentType(primev3messages.MTOShipmentTypePPM), + CounselorRemarks: &counselorRemarks, + PpmShipment: &primev3messages.CreatePPMShipment{ + ExpectedDepartureDate: handlers.FmtDate(expectedDepartureDate), + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{ppmDestinationAddress}, + SitExpected: &sitExpected, + SitLocation: &sitLocation, + SitEstimatedWeight: handlers.FmtPoundPtr(&sitEstimatedWeight), + SitEstimatedEntryDate: handlers.FmtDate(sitEstimatedEntryDate), + SitEstimatedDepartureDate: handlers.FmtDate(sitEstimatedDepartureDate), + EstimatedWeight: handlers.FmtPoundPtr(&estimatedWeight), + HasProGear: &hasProGear, + ProGearWeight: handlers.FmtPoundPtr(&proGearWeight), + SpouseProGearWeight: handlers.FmtPoundPtr(&spouseProGearWeight), + }, + }, + } + + ppmEstimator.On("EstimateIncentiveWithDefaultChecks", + mock.AnythingOfType("*appcontext.appContext"), + mock.AnythingOfType("models.PPMShipment"), + mock.AnythingOfType("*models.PPMShipment")). + Return(models.CentPointer(unit.Cents(estimatedIncentive)), models.CentPointer(unit.Cents(sitEstimatedCost)), nil).Once() + + // Validate incoming payload + suite.NoError(params.Body.Validate(strfmt.Default)) + + response := handler.Handle(params) + suite.IsType(&mtoshipmentops.CreateMTOShipmentOK{}, response) + okResponse := response.(*mtoshipmentops.CreateMTOShipmentOK) + createdShipment := okResponse.Payload + + // Validate outgoing payload + suite.NoError(createdShipment.Validate(strfmt.Default)) + + createdPPM := createdShipment.PpmShipment + + suite.Equal(move.ID.String(), createdShipment.MoveTaskOrderID.String()) + suite.Equal(primev3messages.MTOShipmentTypePPM, createdShipment.ShipmentType) + suite.Equal(primev3messages.MTOShipmentWithoutServiceItemsStatusSUBMITTED, createdShipment.Status) + + suite.Equal(createdShipment.ID.String(), createdPPM.ShipmentID.String()) + suite.Equal(addressWithEmptyStreet1.StreetAddress1, *createdPPM.DestinationAddress.StreetAddress1) + suite.True(len(*createdPPM.DestinationAddress.StreetAddress1) == 0) + + // ************ + // PATCH TESTS + // ************ + ppmEstimator.On("EstimateIncentiveWithDefaultChecks", + mock.AnythingOfType("*appcontext.appContext"), + mock.AnythingOfType("models.PPMShipment"), + mock.AnythingOfType("*models.PPMShipment")). + Return(models.CentPointer(unit.Cents(estimatedIncentive)), models.CentPointer(unit.Cents(sitEstimatedCost)), nil).Times(2) + + ppmEstimator.On("FinalIncentiveWithDefaultChecks", + mock.AnythingOfType("*appcontext.appContext"), + mock.AnythingOfType("models.PPMShipment"), + mock.AnythingOfType("*models.PPMShipment")). + Return(nil, nil) + + patchHandler := UpdateMTOShipmentHandler{ + suite.HandlerConfig(), + shipmentUpdater, + } + + patchReq := httptest.NewRequest("PATCH", fmt.Sprintf("/mto-shipments/%s", createdPPM.ShipmentID.String()), nil) + + var mtoShipment models.MTOShipment + err := suite.DB().Find(&mtoShipment, createdPPM.ShipmentID) + suite.NoError(err) + eTag := etag.GenerateEtag(mtoShipment.UpdatedAt) + patchParams := mtoshipmentops.UpdateMTOShipmentParams{ + HTTPRequest: patchReq, + MtoShipmentID: createdPPM.ShipmentID, + IfMatch: eTag, + } + patchParams.Body = &primev3messages.UpdateMTOShipment{ + ShipmentType: primev3messages.MTOShipmentTypePPM, + } + // ************************************************************************************* + // ************************************************************************************* + // Run with whitespace in destination street 1. Whitespace will be trimmed and seen as + // as empty on the server side. + // ************************************************************************************* + ppmDestinationAddressOptionalStreet1ContainingWhitespaces := primev3messages.PPMDestinationAddress{ + City: models.StringPointer("SomeCity"), + Country: models.StringPointer("US"), + PostalCode: models.StringPointer("90210"), + State: models.StringPointer("CA"), + StreetAddress1: models.StringPointer(" "), //whitespace + } + patchParams.Body.PpmShipment = &primev3messages.UpdatePPMShipment{ + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{ppmDestinationAddressOptionalStreet1ContainingWhitespaces}, + } + + // Validate incoming payload + suite.NoError(patchParams.Body.Validate(strfmt.Default)) + + patchResponse := patchHandler.Handle(patchParams) + suite.IsType(&mtoshipmentops.UpdateMTOShipmentOK{}, patchResponse) + okPatchResponse := patchResponse.(*mtoshipmentops.UpdateMTOShipmentOK) + updatedShipment := okPatchResponse.Payload + + // Validate outgoing payload + suite.NoError(updatedShipment.Validate(strfmt.Default)) + + updatedPPM := updatedShipment.PpmShipment + suite.Equal(ppmDestinationAddressOptionalStreet1ContainingWhitespaces.City, updatedPPM.DestinationAddress.City) + // test whitespace has been trimmed. it should not be equal after update + suite.NotEqual(ppmDestinationAddressOptionalStreet1ContainingWhitespaces.StreetAddress1, updatedPPM.DestinationAddress.StreetAddress1) + // verify street address1 is returned as empty string + suite.True(len(*updatedPPM.DestinationAddress.StreetAddress1) == 0) + }) + suite.Run("Successful POST with Shuttle service items without primeEstimatedWeight - Integration Test", func() { // Under Test: CreateMTOShipment handler code // Setup: Create an mto shipment on an available move diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload.go b/pkg/handlers/primeapiv3/payloads/model_to_payload.go index a3c88a44148..817b85724d9 100644 --- a/pkg/handlers/primeapiv3/payloads/model_to_payload.go +++ b/pkg/handlers/primeapiv3/payloads/model_to_payload.go @@ -211,6 +211,32 @@ func Address(address *models.Address) *primev3messages.Address { } } +// PPM Destination payload +func PPMDestinationAddress(address *models.Address) *primev3messages.PPMDestinationAddress { + if address == nil { + return nil + } + payload := &primev3messages.PPMDestinationAddress{ + ID: strfmt.UUID(address.ID.String()), + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + City: &address.City, + State: &address.State, + PostalCode: &address.PostalCode, + Country: Country(address.Country), + ETag: etag.GenerateEtag(address.UpdatedAt), + County: &address.County, + } + // Street address 1 is optional per business rule but not nullable on the database level. + // Check if streetAddress 1 is using place holder value to represent 'NULL'. + // If so return empty string. + if strings.EqualFold(*payload.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) { + payload.StreetAddress1 = models.StringPointer("") + } + return payload +} + // StorageFacility payload func StorageFacility(storage *models.StorageFacility) *primev3messages.StorageFacility { if storage == nil { @@ -455,7 +481,7 @@ func PPMShipment(ppmShipment *models.PPMShipment) *primev3messages.PPMShipment { payloadPPMShipment.PickupAddress = Address(ppmShipment.PickupAddress) } if ppmShipment.DestinationAddress != nil { - payloadPPMShipment.DestinationAddress = Address(ppmShipment.DestinationAddress) + payloadPPMShipment.DestinationAddress = PPMDestinationAddress(ppmShipment.DestinationAddress) } if ppmShipment.SecondaryPickupAddress != nil { payloadPPMShipment.SecondaryPickupAddress = Address(ppmShipment.SecondaryPickupAddress) @@ -572,7 +598,7 @@ func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primev3mes payload.PpmShipment.TertiaryPickupAddress = Address(mtoShipment.PPMShipment.TertiaryPickupAddress) } if mtoShipment.PPMShipment.DestinationAddress != nil { - payload.PpmShipment.DestinationAddress = Address(mtoShipment.PPMShipment.DestinationAddress) + payload.PpmShipment.DestinationAddress = PPMDestinationAddress(mtoShipment.PPMShipment.DestinationAddress) } if mtoShipment.PPMShipment.SecondaryDestinationAddress != nil { payload.PpmShipment.SecondaryDestinationAddress = Address(mtoShipment.PPMShipment.SecondaryDestinationAddress) diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go b/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go index b888d785c81..51abbc865f5 100644 --- a/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go +++ b/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go @@ -526,6 +526,39 @@ func (suite *PayloadsSuite) TestPPMShipment() { suite.Equal(strfmt.UUID(ppmShipment.ID.String()), result.ID) } +func (suite *PayloadsSuite) TestPPMShipmentContainingOptionalDestinationStreet1() { + now := time.Now() + ppmShipment := &models.PPMShipment{ + ID: uuid.Must(uuid.NewV4()), + DestinationAddress: &models.Address{ + ID: uuid.Must(uuid.NewV4()), + StreetAddress1: models.STREET_ADDRESS_1_NOT_PROVIDED, + StreetAddress2: models.StringPointer("1"), + StreetAddress3: models.StringPointer("2"), + City: "SomeCity", + State: "CA", + PostalCode: "90210", + County: "SomeCounty", + UpdatedAt: now, + }, + } + + result := PPMShipment(ppmShipment) + + eTag := etag.GenerateEtag(now) + + suite.NotNil(result) + // expecting empty string on the response side to simulate nothing was provided. + suite.Equal(result.DestinationAddress.StreetAddress1, models.StringPointer("")) + suite.Equal(result.DestinationAddress.StreetAddress2, ppmShipment.DestinationAddress.StreetAddress2) + suite.Equal(result.DestinationAddress.StreetAddress3, ppmShipment.DestinationAddress.StreetAddress3) + suite.Equal(*result.DestinationAddress.City, ppmShipment.DestinationAddress.City) + suite.Equal(*result.DestinationAddress.State, ppmShipment.DestinationAddress.State) + suite.Equal(*result.DestinationAddress.PostalCode, ppmShipment.DestinationAddress.PostalCode) + suite.Equal(*result.DestinationAddress.County, ppmShipment.DestinationAddress.County) + suite.Equal(result.DestinationAddress.ETag, eTag) +} + func (suite *PayloadsSuite) TestMTOServiceItem() { sitPostalCode := "55555" mtoServiceItemDOFSIT := &models.MTOServiceItem{ diff --git a/pkg/handlers/primeapiv3/payloads/payload_to_model.go b/pkg/handlers/primeapiv3/payloads/payload_to_model.go index 25e9045f92f..3b8a57c5096 100644 --- a/pkg/handlers/primeapiv3/payloads/payload_to_model.go +++ b/pkg/handlers/primeapiv3/payloads/payload_to_model.go @@ -1,6 +1,7 @@ package payloads import ( + "strings" "time" "github.com/go-openapi/strfmt" @@ -59,6 +60,43 @@ func AddressModel(address *primev3messages.Address) *models.Address { return modelAddress } +func PPMDestinationAddressModel(address *primev3messages.PPMDestinationAddress) *models.Address { + // To check if the model is intended to be blank, we'll look at ID and City, State, PostalCode + // We should always have ID if the user intends to update an Address, + // and City, State, PostalCode is a required field on creation. If both are blank, it should be treated as nil. + var blankSwaggerID strfmt.UUID + // unlike other addresses PPM destination address can be created without StreetAddress1 + if address == nil || (address.ID == blankSwaggerID && address.City == nil && address.State == nil && address.PostalCode == nil) { + return nil + } + modelAddress := &models.Address{ + ID: uuid.FromStringOrNil(address.ID.String()), + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + if address.StreetAddress1 != nil && len(strings.Trim(*address.StreetAddress1, " ")) > 0 { + modelAddress.StreetAddress1 = *address.StreetAddress1 + } else { + // Street address 1 is optional for certain business context but not nullable on the database level. + // Use place holder text to represent NULL. + modelAddress.StreetAddress1 = models.STREET_ADDRESS_1_NOT_PROVIDED + } + if address.City != nil { + modelAddress.City = *address.City + } + if address.State != nil { + modelAddress.State = *address.State + } + if address.PostalCode != nil { + modelAddress.PostalCode = *address.PostalCode + } + if address.Country != nil { + modelAddress.Country = CountryModel(address.Country) + } + return modelAddress +} + // ReweighModelFromUpdate model func ReweighModelFromUpdate(reweigh *primev3messages.UpdateReweigh, reweighID strfmt.UUID, mtoShipmentID strfmt.UUID) *models.Reweigh { if reweigh == nil { @@ -297,7 +335,7 @@ func PPMShipmentModelFromCreate(ppmShipment *primev3messages.CreatePPMShipment) model.HasTertiaryPickupAddress = handlers.FmtBool(true) } - addressModel = AddressModel(&ppmShipment.DestinationAddress.Address) + addressModel = PPMDestinationAddressModel(&ppmShipment.DestinationAddress.PPMDestinationAddress) if addressModel != nil { model.DestinationAddress = addressModel } @@ -518,7 +556,7 @@ func PPMShipmentModelFromUpdate(ppmShipment *primev3messages.UpdatePPMShipment) } } - addressModel = AddressModel(&ppmShipment.DestinationAddress.Address) + addressModel = PPMDestinationAddressModel(&ppmShipment.DestinationAddress.PPMDestinationAddress) if addressModel != nil { model.DestinationAddress = addressModel } diff --git a/pkg/handlers/primeapiv3/payloads/payload_to_model_test.go b/pkg/handlers/primeapiv3/payloads/payload_to_model_test.go index 5d9c18bd6ad..0e1f99464dd 100644 --- a/pkg/handlers/primeapiv3/payloads/payload_to_model_test.go +++ b/pkg/handlers/primeapiv3/payloads/payload_to_model_test.go @@ -567,7 +567,7 @@ func (suite *PayloadsSuite) TestPPMShipmentModelFromCreate() { var pickupAddress primev3messages.Address var secondaryPickupAddress primev3messages.Address var tertiaryPickupAddress primev3messages.Address - var destinationAddress primev3messages.Address + var destinationAddress primev3messages.PPMDestinationAddress var secondaryDestinationAddress primev3messages.Address var tertiaryDestinationAddress primev3messages.Address @@ -579,7 +579,7 @@ func (suite *PayloadsSuite) TestPPMShipmentModelFromCreate() { StreetAddress2: address.StreetAddress2, StreetAddress3: address.StreetAddress3, } - destinationAddress = primev3messages.Address{ + destinationAddress = primev3messages.PPMDestinationAddress{ City: &address.City, PostalCode: &address.PostalCode, State: &address.State, @@ -621,11 +621,13 @@ func (suite *PayloadsSuite) TestPPMShipmentModelFromCreate() { } ppmShipment := primev3messages.CreatePPMShipment{ - ExpectedDepartureDate: expectedDepartureDate, - PickupAddress: struct{ primev3messages.Address }{pickupAddress}, - SecondaryPickupAddress: struct{ primev3messages.Address }{secondaryPickupAddress}, - TertiaryPickupAddress: struct{ primev3messages.Address }{tertiaryPickupAddress}, - DestinationAddress: struct{ primev3messages.Address }{destinationAddress}, + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + SecondaryPickupAddress: struct{ primev3messages.Address }{secondaryPickupAddress}, + TertiaryPickupAddress: struct{ primev3messages.Address }{tertiaryPickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, SecondaryDestinationAddress: struct{ primev3messages.Address }{secondaryDestinationAddress}, TertiaryDestinationAddress: struct{ primev3messages.Address }{tertiaryDestinationAddress}, SitExpected: &sitExpected, @@ -651,6 +653,151 @@ func (suite *PayloadsSuite) TestPPMShipmentModelFromCreate() { suite.NotNil(model) } +func (suite *PayloadsSuite) TestPPMShipmentModelWithOptionalDestinationStreet1FromCreate() { + time := time.Now() + expectedDepartureDate := handlers.FmtDatePtr(&time) + + address := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "state", + PostalCode: "12345", + } + + var pickupAddress primev3messages.Address + var destinationAddress primev3messages.PPMDestinationAddress + + pickupAddress = primev3messages.Address{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + destinationAddress = primev3messages.PPMDestinationAddress{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: models.StringPointer(""), // empty string + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + ppmShipment := primev3messages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, + } + + model := PPMShipmentModelFromCreate(&ppmShipment) + + suite.NotNil(model) + suite.Equal(models.PPMShipmentStatusSubmitted, model.Status) + suite.Equal(model.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test when street address 1 contains white spaces + destinationAddress.StreetAddress1 = models.StringPointer(" ") + ppmShipmentWhiteSpaces := primev3messages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, + } + + model2 := PPMShipmentModelFromCreate(&ppmShipmentWhiteSpaces) + suite.Equal(model2.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test with valid street address 2 + streetAddress1 := "1234 Street" + destinationAddress.StreetAddress1 = &streetAddress1 + ppmShipmentValidDestinatonStreet1 := primev3messages.CreatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, + } + + model3 := PPMShipmentModelFromCreate(&ppmShipmentValidDestinatonStreet1) + suite.Equal(model3.DestinationAddress.StreetAddress1, streetAddress1) +} + +func (suite *PayloadsSuite) TestPPMShipmentModelWithOptionalDestinationStreet1FromUpdate() { + time := time.Now() + expectedDepartureDate := handlers.FmtDatePtr(&time) + + address := models.Address{ + StreetAddress1: "some address", + City: "city", + State: "state", + PostalCode: "12345", + } + + var pickupAddress primev3messages.Address + var destinationAddress primev3messages.PPMDestinationAddress + + pickupAddress = primev3messages.Address{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: &address.StreetAddress1, + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + destinationAddress = primev3messages.PPMDestinationAddress{ + City: &address.City, + PostalCode: &address.PostalCode, + State: &address.State, + StreetAddress1: models.StringPointer(""), // empty string + StreetAddress2: address.StreetAddress2, + StreetAddress3: address.StreetAddress3, + } + + ppmShipment := primev3messages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, + } + + model := PPMShipmentModelFromUpdate(&ppmShipment) + + suite.NotNil(model) + suite.Equal(model.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test when street address 1 contains white spaces + destinationAddress.StreetAddress1 = models.StringPointer(" ") + ppmShipmentWhiteSpaces := primev3messages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, + } + + model2 := PPMShipmentModelFromUpdate(&ppmShipmentWhiteSpaces) + suite.Equal(model2.DestinationAddress.StreetAddress1, models.STREET_ADDRESS_1_NOT_PROVIDED) + + // test with valid street address 2 + streetAddress1 := "1234 Street" + destinationAddress.StreetAddress1 = &streetAddress1 + ppmShipmentValidDestinatonStreet1 := primev3messages.UpdatePPMShipment{ + ExpectedDepartureDate: expectedDepartureDate, + PickupAddress: struct{ primev3messages.Address }{pickupAddress}, + DestinationAddress: struct { + primev3messages.PPMDestinationAddress + }{destinationAddress}, + } + + model3 := PPMShipmentModelFromUpdate(&ppmShipmentValidDestinatonStreet1) + suite.Equal(model3.DestinationAddress.StreetAddress1, streetAddress1) +} + func (suite *PayloadsSuite) TestCountryModel_WithValidCountry() { countryName := "US" result := CountryModel(&countryName) diff --git a/pkg/models/address.go b/pkg/models/address.go index fa4ec5b6767..edd73ea34ce 100644 --- a/pkg/models/address.go +++ b/pkg/models/address.go @@ -13,6 +13,8 @@ import ( "go.uber.org/zap/zapcore" ) +const STREET_ADDRESS_1_NOT_PROVIDED string = "n/a" + // Address is an address type Address struct { ID uuid.UUID `json:"id" db:"id"` diff --git a/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.jsx b/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.jsx index c98a73e5bdc..8a81865caaf 100644 --- a/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.jsx +++ b/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.jsx @@ -18,7 +18,7 @@ import { searchTransportationOffices } from 'services/internalApi'; import SERVICE_MEMBER_AGENCIES from 'content/serviceMemberAgencies'; import { AddressFields } from 'components/form/AddressFields/AddressFields'; import { OptionalAddressSchema } from 'components/Customer/MtoShipmentForm/validationSchemas'; -import { requiredAddressSchema } from 'utils/validation'; +import { requiredAddressSchema, partialRequiredAddressSchema } from 'utils/validation'; import { isBooleanFlagEnabled } from 'utils/featureFlags'; import RequiredTag from 'components/form/RequiredTag'; @@ -37,7 +37,7 @@ let validationShape = { address: requiredAddressSchema, }), destinationAddress: Yup.object().shape({ - address: requiredAddressSchema, + address: partialRequiredAddressSchema, }), secondaryPickupAddress: Yup.object().shape({ address: OptionalAddressSchema, @@ -299,6 +299,9 @@ const DateAndLocationForm = ({ mtoShipment, destinationDutyLocation, serviceMemb ( <>

Please input your destination address.

diff --git a/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.test.jsx b/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.test.jsx index c7bd1482bc3..ef1030c347f 100644 --- a/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.test.jsx +++ b/src/components/Customer/PPM/Booking/DateAndLocationForm/DateAndLocationForm.test.jsx @@ -265,6 +265,43 @@ describe('validates form fields and displays error messages', () => { }); }); }); + + it('destination address 1 is empty passes validation schema - destination street 1 is OPTIONAL', async () => { + await act(async () => { + render(); + + // type something in for destination address 1 + await userEvent.type( + document.querySelector('input[name="destinationAddress.address.streetAddress1"]'), + '1234 Street', + ); + // now clear out text, should not raise required alert because street is OPTIONAL in DateAndLocationForm context. + await userEvent.clear(document.querySelector('input[name="destinationAddress.address.streetAddress1"]')); + + // must fail validation + await userEvent.type(document.querySelector('input[name="pickupAddress.address.postalCode"]'), '1111'); + + await userEvent.click(screen.getByRole('button', { name: 'Save & Continue' })); + + await waitFor(() => { + expect(screen.getByRole('button', { name: 'Save & Continue' })).toBeDisabled(); + const requiredAlerts = screen.getAllByRole('alert'); + // only expecting postalCode alert + expect(requiredAlerts.length).toBe(1); + + // 'Required' labelHint on address display. expecting a total of 7(2 for pickup address and 3 destination address with 2 misc). + // This is to verify Required labelHints are displayed correctly for PPM onboarding/edit for the destination address + // street 1 is now OPTIONAL. If this fails it means addtional labelHints have been introduced elsewhere within the control. + const hints = document.getElementsByClassName('usa-hint'); + expect(hints.length).toBe(7); + // verify labelHints are actually 'Optional' + for (let i = 0; i < hints.length; i += 1) { + expect(hints[i]).toHaveTextContent('Required'); + } + }); + }); + }); + it('displays tertiary pickup Address input when hasTertiaryPickupAddress is true', async () => { await act(async () => { render(); diff --git a/src/components/Customer/PPM/Closeout/AboutForm/AboutForm.test.jsx b/src/components/Customer/PPM/Closeout/AboutForm/AboutForm.test.jsx index 2449eb3487b..476a3defdc3 100644 --- a/src/components/Customer/PPM/Closeout/AboutForm/AboutForm.test.jsx +++ b/src/components/Customer/PPM/Closeout/AboutForm/AboutForm.test.jsx @@ -219,6 +219,40 @@ describe('AboutForm component', () => { await expect(screen.getByRole('button', { name: 'Save & Continue' })).toBeEnabled(); }); + it('PPM destination street1 is required', async () => { + render(); + await expect(screen.getByRole('button', { name: 'Save & Continue' })).toBeEnabled(); + + // Start controlled test case to verify everything is working. + const input = await document.querySelector('input[name="destinationAddress.streetAddress1"]'); + expect(input).toBeInTheDocument(); + // clear + await userEvent.clear(input); + await userEvent.tab(); + // verify Required alert is displayed + const requiredAlerts = screen.getByRole('alert'); + expect(requiredAlerts).toHaveTextContent('Required'); + + // verify validation disables save button. destination street 1 is required only in PPM doc upload while + // it's OPTIONAL during onboarding..etc... + await expect(screen.getByRole('button', { name: 'Save & Continue' })).not.toBeEnabled(); + + // verify save is enabled + await userEvent.type(input, '123 Street'); + await expect(screen.getByRole('button', { name: 'Save & Continue' })).toBeEnabled(); + + // 'Optional' labelHint on address display. expecting a total of 9(3 for pickup address, 3 destination address, 3 w2 address). + // This is to verify Required labelHints are displayed correctly for PPM doc uploading for the destination address + // street 1 is now OPTIONAL for onboarding but required for PPM doc upload. If this fails it means addtional labelHints + // have been introduced elsewhere within the control. + const hints = document.getElementsByClassName('usa-hint'); + expect(hints.length).toBe(9); + // verify labelHints are actually 'Optional' + for (let i = 0; i < hints.length; i += 1) { + expect(hints[i]).toHaveTextContent('Required'); + } + }); + it('displays type error messages for invalid input', async () => { render(); diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx index f3685725c20..231668d78b0 100644 --- a/src/components/Office/ShipmentForm/ShipmentForm.jsx +++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx @@ -1402,6 +1402,7 @@ const ShipmentForm = (props) => { ( <> {fields} diff --git a/src/components/Office/ShipmentForm/ShipmentForm.test.jsx b/src/components/Office/ShipmentForm/ShipmentForm.test.jsx index d6f3c01a1d8..dc27b9ff579 100644 --- a/src/components/Office/ShipmentForm/ShipmentForm.test.jsx +++ b/src/components/Office/ShipmentForm/ShipmentForm.test.jsx @@ -1365,11 +1365,11 @@ describe('ShipmentForm component', () => { await userEvent.selectOptions(pickupStateInput, 'CA'); await userEvent.type(screen.getAllByLabelText('ZIP')[0], '90210'); - await userEvent.type(screen.getAllByLabelText('Address 1')[1], 'Test Street 3'); - await userEvent.type(screen.getAllByLabelText('City')[1], 'TestTwo City'); + await userEvent.type(screen.getAllByLabelText(/Address 1/)[1], 'Test Street 3'); + await userEvent.type(screen.getAllByLabelText(/City/)[1], 'TestTwo City'); const destinationStateInput = screen.getAllByLabelText('State')[1]; await userEvent.selectOptions(destinationStateInput, 'CA'); - await userEvent.type(screen.getAllByLabelText('ZIP')[1], '90210'); + await userEvent.type(screen.getAllByLabelText(/ZIP/)[1], '90210'); await userEvent.type(screen.getByLabelText('Estimated PPM weight'), '1000'); @@ -1526,6 +1526,43 @@ describe('ShipmentForm component', () => { expect(await screen.findByTestId('tag')).toHaveTextContent('PPM'); }); + + it('PPM - destination address street 1 is OPTIONAL', async () => { + renderWithRouter( + , + ); + + expect(await screen.findByTestId('tag')).toHaveTextContent('PPM'); + + // controlled test. we expect alert to be raised if we type in whitespace to trigger required alert + // for pickup + await userEvent.type(document.querySelector('input[name="pickup.address.streetAddress1"]'), ' '); + await userEvent.tab(); + await waitFor(() => { + const requiredAlerts = screen.getAllByRole('alert'); + expect(requiredAlerts.length).toBe(1); + }); + + await userEvent.type(document.querySelector('input[name="pickup.address.streetAddress1"]'), '123 New Street'); + await userEvent.tab(); + await waitFor(() => { + // verify no alerts are present + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + }); + + // test that destination address street1 is OPTIONAL and not raise any required alert + await userEvent.type(document.querySelector('input[name="destination.address.streetAddress1"]'), ' '); + await userEvent.tab(); + await waitFor(() => { + // verify required alert was not raised + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + }); + }); }); describe('TOO editing an already existing PPM shipment', () => { @@ -1571,7 +1608,7 @@ describe('ShipmentForm component', () => { mockPPMShipment.ppmShipment.secondaryPickupAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[2]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[2]).toHaveValue( mockPPMShipment.ppmShipment.destinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[2]).toHaveValue( @@ -1583,23 +1620,23 @@ describe('ShipmentForm component', () => { expect(await screen.getAllByLabelText('State')[2]).toHaveValue( mockPPMShipment.ppmShipment.destinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[2]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[2]).toHaveValue( mockPPMShipment.ppmShipment.destinationAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.streetAddress2, ); - expect(await screen.getAllByLabelText('City')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/City/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.city, ); expect(await screen.getAllByLabelText('State')[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.postalCode, ); @@ -1694,7 +1731,7 @@ describe('ShipmentForm component', () => { mockPPMShipment.ppmShipment.secondaryPickupAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[2]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[2]).toHaveValue( mockPPMShipment.ppmShipment.destinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[2]).toHaveValue( @@ -1706,23 +1743,23 @@ describe('ShipmentForm component', () => { expect(await screen.getAllByLabelText('State')[2]).toHaveValue( mockPPMShipment.ppmShipment.destinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[2]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[2]).toHaveValue( mockPPMShipment.ppmShipment.destinationAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.streetAddress2, ); - expect(await screen.getAllByLabelText('City')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/City/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.city, ); expect(await screen.getAllByLabelText('State')[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[3]).toHaveValue( mockPPMShipment.ppmShipment.secondaryDestinationAddress.postalCode, ); @@ -1732,7 +1769,52 @@ describe('ShipmentForm component', () => { expect(screen.getAllByLabelText('Yes')[2]).toBeChecked(); expect(screen.getAllByLabelText('No')[2]).not.toBeChecked(); }); + + it('test destination address street 1 is OPTIONAL', async () => { + isBooleanFlagEnabled.mockImplementation(() => Promise.resolve(true)); + renderWithRouter( + , + ); + + await userEvent.clear(document.querySelector('input[name="pickup.address.streetAddress1"]')); + await userEvent.tab(); + await waitFor(() => { + const requiredAlerts = screen.getAllByRole('alert'); + expect(requiredAlerts.length).toBe(1); + }); + + await userEvent.type(document.querySelector('input[name="pickup.address.streetAddress1"]'), '123 New Street'); + await userEvent.tab(); + await waitFor(() => { + // verify no alerts are present + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + }); + + // test that destination address street1 is OPTIONAL and not raise any required alert + await userEvent.clear(document.querySelector('input[name="destination.address.streetAddress1"]')); + await userEvent.tab(); + await waitFor(() => { + // verify required alert was not raised + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + + // 'Optional' labelHint on address display. expecting a total of 9(2 for pickup address and 3 destination address, 4 for secondary addrs). + // This is to verify Optional labelHints are displayed correctly for PPM onboarding/edit for the destination address + // street 1 is now OPTIONAL. If this fails it means addtional labelHints have been introduced elsewhere within the control. + const hints = document.getElementsByClassName('usa-hint'); + expect(hints.length).toBe(9); + // verify labelHints are actually 'Optional' + for (let i = 0; i < hints.length; i += 1) { + expect(hints[i]).toHaveTextContent('Optional'); + } + }); + }); }); + it('renders the PPM shipment form with pre-filled requested values for Advance Page', async () => { renderWithRouter( { const addressFieldsUUID = useRef(uuidv4()); @@ -66,6 +69,19 @@ export const AddressFields = ({ ); } + const getAddress1LabelHintText = (labelHint, address1Label) => { + if (address1Label === null) { + return labelHint; + } + + // Override default and use what is passed in. + if (address1Label && address1Label.trim().length > 0) { + return address1Label; + } + + return null; + }; + return (
{render( @@ -74,7 +90,7 @@ export const AddressFields = ({ label="Address 1" id={`mailingAddress1_${addressFieldsUUID.current}`} name={`${name}.streetAddress1`} - labelHint={labelHintProp} + labelHint={getAddress1LabelHintText(labelHintProp, address1LabelHint)} validate={validators?.streetAddress1} /> fields, validators: {}, formikFunctionsToValidatePostalCodeOnChange: null, + address1LabelHint: null, }; export default AddressFields; diff --git a/src/pages/Office/ServicesCounselingEditShipmentDetails/ServicesCounselingEditShipmentDetails.test.jsx b/src/pages/Office/ServicesCounselingEditShipmentDetails/ServicesCounselingEditShipmentDetails.test.jsx index ce4d28f1e5b..6134ef8f8b7 100644 --- a/src/pages/Office/ServicesCounselingEditShipmentDetails/ServicesCounselingEditShipmentDetails.test.jsx +++ b/src/pages/Office/ServicesCounselingEditShipmentDetails/ServicesCounselingEditShipmentDetails.test.jsx @@ -396,7 +396,7 @@ describe('ServicesCounselingEditShipmentDetails component', () => { ppmShipment.ppmShipment.secondaryPickupAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[2]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[2]).toHaveValue( ppmShipment.ppmShipment.destinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[2]).toHaveValue( @@ -404,23 +404,23 @@ describe('ServicesCounselingEditShipmentDetails component', () => { ); expect(await screen.getAllByLabelText('City')[2]).toHaveValue(ppmShipment.ppmShipment.destinationAddress.city); expect(await screen.getAllByLabelText('State')[2]).toHaveValue(ppmShipment.ppmShipment.destinationAddress.state); - expect(await screen.getAllByLabelText('ZIP')[2]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[2]).toHaveValue( ppmShipment.ppmShipment.destinationAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[3]).toHaveValue( ppmShipment.ppmShipment.secondaryDestinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[3]).toHaveValue( ppmShipment.ppmShipment.secondaryDestinationAddress.streetAddress2, ); - expect(await screen.getAllByLabelText('City')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/City/)[3]).toHaveValue( ppmShipment.ppmShipment.secondaryDestinationAddress.city, ); expect(await screen.getAllByLabelText('State')[3]).toHaveValue( ppmShipment.ppmShipment.secondaryDestinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[3]).toHaveValue( ppmShipment.ppmShipment.secondaryDestinationAddress.postalCode, ); diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx index 748703682c1..fdfa1c75c2b 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx @@ -18,7 +18,7 @@ import WizardNavigation from 'components/Customer/WizardNavigation/WizardNavigat import { isEmpty, isValidWeight } from 'shared/utils'; import { formatAddressForPrimeAPI, formatSwaggerDate } from 'utils/formatters'; import { setFlashMessage as setFlashMessageAction } from 'store/flash/actions'; -import { requiredAddressSchema } from 'utils/validation'; +import { requiredAddressSchema, partialRequiredAddressSchema } from 'utils/validation'; import PrimeUIShipmentCreateForm from 'pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm'; import { OptionalAddressSchema } from 'components/Customer/MtoShipmentForm/validationSchemas'; import { SHIPMENT_OPTIONS, SHIPMENT_TYPES } from 'shared/constants'; @@ -405,7 +405,7 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { pickupAddress: requiredAddressSchema.required('Required'), secondaryPickupAddress: OptionalAddressSchema, tertiaryPickupAddress: OptionalAddressSchema, - destinationAddress: requiredAddressSchema.required('Required'), + destinationAddress: partialRequiredAddressSchema.required('Required'), secondaryDestinationAddress: OptionalAddressSchema, tertiaryDestinationAddress: OptionalAddressSchema, sitExpected: Yup.boolean().required('Required'), diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.test.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.test.jsx index 662c6633b93..a7487d9f68f 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.test.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.test.jsx @@ -80,3 +80,38 @@ describe('successful submission of form', () => { }); }); }); + +describe('Create PPM', () => { + it('test destination address street 1 is OPTIONAL', async () => { + createPrimeMTOShipmentV3.mockReturnValue({}); + + render(mockedComponent); + + await userEvent.selectOptions(screen.getByLabelText('Shipment type'), 'PPM'); + + // Start controlled test case to verify everything is working. + let input = await document.querySelector('input[name="ppmShipment.pickupAddress.streetAddress1"]'); + expect(input).toBeInTheDocument(); + // enter required street 1 for pickup + await userEvent.type(input, '123 Street'); + // clear + await userEvent.clear(input); + await userEvent.tab(); + // verify Required alert is displayed + const requiredAlerts = screen.getByRole('alert'); + expect(requiredAlerts).toHaveTextContent('Required'); + // make valid again to clear alert + await userEvent.type(input, '123 Street'); + + // Verify destination address street 1 is OPTIONAL. + input = await document.querySelector('input[name="ppmShipment.destinationAddress.streetAddress1"]'); + expect(input).toBeInTheDocument(); + // enter something + await userEvent.type(input, '123 Street'); + // clear + await userEvent.clear(input); + await userEvent.tab(); + // verify no validation is displayed after clearing destination address street 1 because it's OPTIONAL + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + }); +}); diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx index db825c18590..46b577091d3 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx @@ -192,6 +192,7 @@ const PrimeUIShipmentCreateForm = () => { ( <> {fields} diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx index 419f8ec2388..a25098bd10b 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx @@ -215,10 +215,10 @@ describe('PrimeUIShipmentCreateForm', () => { expect(await screen.getAllByLabelText('State')[0]).toHaveValue(initialValues.ppmShipment.pickupAddress.state); expect(await screen.getAllByLabelText('ZIP')[0]).toHaveValue(initialValues.ppmShipment.pickupAddress.postalCode); - expect(await screen.getAllByLabelText('Address 1')[1]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[1]).toHaveValue( initialValues.ppmShipment.secondaryPickupAddress.streetAddress1, ); - expect(await screen.getAllByLabelText('City')[1]).toHaveValue( + expect(await screen.getAllByLabelText(/City/)[1]).toHaveValue( initialValues.ppmShipment.secondaryPickupAddress.city, ); expect(await screen.getAllByLabelText('State')[1]).toHaveValue( diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.jsx index bb408d21f55..0aa9f5e0e2a 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.jsx @@ -18,7 +18,7 @@ import styles from 'components/Office/CustomerContactInfoForm/CustomerContactInf import { Form } from 'components/form/Form'; import formStyles from 'styles/form.module.scss'; import WizardNavigation from 'components/Customer/WizardNavigation/WizardNavigation'; -import { requiredAddressSchema, addressSchema } from 'utils/validation'; +import { requiredAddressSchema, addressSchema, partialRequiredAddressSchema } from 'utils/validation'; import { isEmpty, isValidWeight } from 'shared/utils'; import { formatAddressForPrimeAPI, @@ -303,6 +303,7 @@ const PrimeUIShipmentUpdate = ({ setFlashMessage }) => { }, counselorRemarks: shipment.counselorRemarks || '', }; + validationSchema = Yup.object().shape({ ppmShipment: Yup.object().shape({ expectedDepartureDate: Yup.date() @@ -311,7 +312,7 @@ const PrimeUIShipmentUpdate = ({ setFlashMessage }) => { pickupAddress: requiredAddressSchema.required('Required'), secondaryPickupAddress: OptionalAddressSchema, tertiaryPickupAddress: OptionalAddressSchema, - destinationAddress: requiredAddressSchema.required('Required'), + destinationAddress: partialRequiredAddressSchema.required('Required'), secondaryDestinationAddress: OptionalAddressSchema, tertiaryDestinationAddress: OptionalAddressSchema, sitExpected: Yup.boolean().required('Required'), diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.test.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.test.jsx index 81154951703..f7e8ad3be2f 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.test.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdate.test.jsx @@ -479,4 +479,35 @@ describe('Update Shipment Page for PPM', () => { expect(await screen.findByText('Weights')).toBeInTheDocument(); expect(await screen.findByText('Remarks')).toBeInTheDocument(); }); + + it('test destination address street 1 is OPTIONAL', async () => { + usePrimeSimulatorGetMove.mockReturnValue(readyReturnValue); + + render(ppmMockedComponent); + + // Start controlled test case to verify everything is working. + let input = await document.querySelector('input[name="ppmShipment.pickupAddress.streetAddress1"]'); + expect(input).toBeInTheDocument(); + // enter required street 1 for pickup + await userEvent.type(input, '123 Street'); + // clear + await userEvent.clear(input); + await userEvent.tab(); + // verify Required alert is displayed + const requiredAlerts = screen.getByRole('alert'); + expect(requiredAlerts).toHaveTextContent('Required'); + // make valid again to clear alert + await userEvent.type(input, '123 Street'); + + // Verify destination address street 1 is OPTIONAL. + input = await document.querySelector('input[name="ppmShipment.destinationAddress.streetAddress1"]'); + expect(input).toBeInTheDocument(); + // enter something + await userEvent.type(input, '123 Street'); + // clear + await userEvent.clear(input); + await userEvent.tab(); + // verify no validation is displayed after clearing destination address street 1 because it's OPTIONAL + expect(screen.queryByRole('alert')).not.toBeInTheDocument(); + }); }); diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.jsx index 040737e4898..33286b9abfc 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.jsx @@ -111,6 +111,7 @@ const PrimeUIShipmentUpdatePPMForm = () => { ( <> {fields} diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.test.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.test.jsx index be3ea189cd7..2878c33af59 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.test.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentUpdatePPMForm.test.jsx @@ -216,7 +216,7 @@ describe('PrimeUIShipmentUpdatePPMForm', () => { initialValues.ppmShipment.tertiaryPickupAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[3]).toHaveValue( initialValues.ppmShipment.destinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[3]).toHaveValue( @@ -224,39 +224,39 @@ describe('PrimeUIShipmentUpdatePPMForm', () => { ); expect(await screen.getAllByLabelText('City')[3]).toHaveValue(initialValues.ppmShipment.destinationAddress.city); expect(await screen.getAllByLabelText('State')[3]).toHaveValue(initialValues.ppmShipment.destinationAddress.state); - expect(await screen.getAllByLabelText('ZIP')[3]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[3]).toHaveValue( initialValues.ppmShipment.destinationAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[4]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[4]).toHaveValue( initialValues.ppmShipment.secondaryDestinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[4]).toHaveValue( initialValues.ppmShipment.secondaryDestinationAddress.streetAddress2, ); - expect(await screen.getAllByLabelText('City')[4]).toHaveValue( + expect(await screen.getAllByLabelText(/City/)[4]).toHaveValue( initialValues.ppmShipment.secondaryDestinationAddress.city, ); expect(await screen.getAllByLabelText('State')[4]).toHaveValue( initialValues.ppmShipment.secondaryDestinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[4]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[4]).toHaveValue( initialValues.ppmShipment.secondaryDestinationAddress.postalCode, ); - expect(await screen.getAllByLabelText('Address 1')[5]).toHaveValue( + expect(await screen.getAllByLabelText(/Address 1/)[5]).toHaveValue( initialValues.ppmShipment.tertiaryDestinationAddress.streetAddress1, ); expect(await screen.getAllByLabelText(/Address 2/)[5]).toHaveValue( initialValues.ppmShipment.tertiaryDestinationAddress.streetAddress2, ); - expect(await screen.getAllByLabelText('City')[5]).toHaveValue( + expect(await screen.getAllByLabelText(/City/)[5]).toHaveValue( initialValues.ppmShipment.tertiaryDestinationAddress.city, ); expect(await screen.getAllByLabelText('State')[5]).toHaveValue( initialValues.ppmShipment.tertiaryDestinationAddress.state, ); - expect(await screen.getAllByLabelText('ZIP')[5]).toHaveValue( + expect(await screen.getAllByLabelText(/ZIP/)[5]).toHaveValue( initialValues.ppmShipment.tertiaryDestinationAddress.postalCode, ); diff --git a/src/utils/validation.js b/src/utils/validation.js index f8e95f34fa6..f07daecd66c 100644 --- a/src/utils/validation.js +++ b/src/utils/validation.js @@ -85,6 +85,18 @@ export const requiredAddressSchema = Yup.object().shape({ postalCode: Yup.string().matches(ZIP_CODE_REGEX, 'Must be valid zip code').required('Required'), }); +// city, state, postalCode only required +export const partialRequiredAddressSchema = Yup.object().shape({ + streetAddress1: Yup.string(), + streetAddress2: Yup.string(), + city: Yup.string().trim().required('Required'), + state: Yup.string() + .test('', UnsupportedStateErrorMsg, IsSupportedState) + .length(2, 'Must use state abbreviation') + .required('Required'), + postalCode: Yup.string().matches(ZIP_CODE_REGEX, 'Must be valid zip code').required('Required'), +}); + export const requiredW2AddressSchema = Yup.object().shape({ streetAddress1: Yup.string().required('Required'), streetAddress2: Yup.string(), diff --git a/swagger-def/definitions/PPMDestinationAddress.yaml b/swagger-def/definitions/PPMDestinationAddress.yaml new file mode 100644 index 00000000000..546ba833884 --- /dev/null +++ b/swagger-def/definitions/PPMDestinationAddress.yaml @@ -0,0 +1,157 @@ +description: A postal address +type: object +properties: + id: + type: string + format: uuid + example: c56a4180-65aa-42ec-a945-5fd21dec0538 + streetAddress1: + type: string + example: 123 Main Ave + x-nullable: true + title: Street address 1 + streetAddress2: + type: string + example: Apartment 9000 + x-nullable: true + title: Street address 2 + streetAddress3: + type: string + example: Montmârtre + x-nullable: true + title: Address Line 3 + city: + type: string + example: Anytown + title: City + eTag: + type: string + readOnly: true + state: + title: State + type: string + x-display-value: + AL: AL + AK: AK + AR: AR + AZ: AZ + CA: CA + CO: CO + CT: CT + DC: DC + DE: DE + FL: FL + GA: GA + HI: HI + IA: IA + ID: ID + IL: IL + IN: IN + KS: KS + KY: KY + LA: LA + MA: MA + MD: MD + ME: ME + MI: MI + MN: MN + MO: MO + MS: MS + MT: MT + NC: NC + ND: ND + NE: NE + NH: NH + NJ: NJ + NM: NM + NV: NV + NY: NY + OH: OH + OK: OK + OR: OR + PA: PA + RI: RI + SC: SC + SD: SD + TN: TN + TX: TX + UT: UT + VA: VA + VT: VT + WA: WA + WI: WI + WV: WV + WY: WY + enum: + - AL + - AK + - AR + - AZ + - CA + - CO + - CT + - DC + - DE + - FL + - GA + - HI + - IA + - ID + - IL + - IN + - KS + - KY + - LA + - MA + - MD + - ME + - MI + - MN + - MO + - MS + - MT + - NC + - ND + - NE + - NH + - NJ + - NM + - NV + - NY + - OH + - OK + - OR + - PA + - RI + - SC + - SD + - TN + - TX + - UT + - VA + - VT + - WA + - WI + - WV + - WY + postalCode: + type: string + format: zip + title: ZIP + example: '90210' + pattern: '^(\d{5}([\-]\d{4})?)$' + country: + type: string + title: Country + x-nullable: true + example: 'USA' + default: USA + county: + type: string + title: County + x-nullable: true + example: 'LOS ANGELES' +required: + - city + - state + - postalCode diff --git a/swagger-def/definitions/prime/v3/PPMShipment.yaml b/swagger-def/definitions/prime/v3/PPMShipment.yaml index 20d29db9f97..8a29009fd80 100644 --- a/swagger-def/definitions/prime/v3/PPMShipment.yaml +++ b/swagger-def/definitions/prime/v3/PPMShipment.yaml @@ -79,7 +79,7 @@ properties: x-nullable: true x-omitempty: false destinationAddress: - $ref: '../../Address.yaml' + $ref: '../../PPMDestinationAddress.yaml' secondaryDestinationAddress: $ref: '../../Address.yaml' hasSecondaryDestinationAddress: diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index 0e16ad0dbd6..8a753ba2166 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -6031,7 +6031,7 @@ definitions: - $ref: 'definitions/Address.yaml' destinationAddress: allOf: - - $ref: 'definitions/Address.yaml' + - $ref: 'definitions/PPMDestinationAddress.yaml' actualDestinationPostalCode: description: > The actual postal code where the PPM shipment ended. To be filled once the customer has moved the shipment. @@ -6439,7 +6439,7 @@ definitions: - $ref: 'definitions/Address.yaml' destinationAddress: allOf: - - $ref: 'definitions/Address.yaml' + - $ref: 'definitions/PPMDestinationAddress.yaml' secondaryDestinationAddress: allOf: - $ref: 'definitions/Address.yaml' diff --git a/swagger-def/internal.yaml b/swagger-def/internal.yaml index 704ac01f7b6..c79fde5c5a5 100644 --- a/swagger-def/internal.yaml +++ b/swagger-def/internal.yaml @@ -1940,7 +1940,7 @@ definitions: secondaryPickupAddress: $ref: 'definitions/Address.yaml' destinationAddress: - $ref: 'definitions/Address.yaml' + $ref: "definitions/PPMDestinationAddress.yaml" secondaryDestinationAddress: $ref: 'definitions/Address.yaml' tertiaryDestinationAddress: @@ -1999,7 +1999,7 @@ definitions: pattern: ^(\d{5})$ x-nullable: true destinationAddress: - $ref: 'definitions/Address.yaml' + $ref: "definitions/PPMDestinationAddress.yaml" secondaryDestinationAddress: $ref: 'definitions/Address.yaml' hasSecondaryDestinationAddress: diff --git a/swagger-def/prime_v3.yaml b/swagger-def/prime_v3.yaml index fe0411db96e..cd7719184a5 100644 --- a/swagger-def/prime_v3.yaml +++ b/swagger-def/prime_v3.yaml @@ -448,7 +448,7 @@ definitions: destinationAddress: description: The address of the destination location where goods are being delivered to. allOf: - - $ref: 'definitions/Address.yaml' + - $ref: 'definitions/PPMDestinationAddress.yaml' secondaryDestinationAddress: description: An optional secondary address near the destination where goods will be dropped off. allOf: @@ -658,7 +658,7 @@ definitions: description: > The address of the destination location where goods are being delivered to. allOf: - - $ref: 'definitions/Address.yaml' + - $ref: 'definitions/PPMDestinationAddress.yaml' hasSecondaryDestinationAddress: type: boolean x-omitempty: false diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index 229beb014e9..13b7a5f2328 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -6284,7 +6284,7 @@ definitions: - $ref: '#/definitions/Address' destinationAddress: allOf: - - $ref: '#/definitions/Address' + - $ref: '#/definitions/PPMDestinationAddress' actualDestinationPostalCode: description: > The actual postal code where the PPM shipment ended. To be filled once @@ -6717,7 +6717,7 @@ definitions: - $ref: '#/definitions/Address' destinationAddress: allOf: - - $ref: '#/definitions/Address' + - $ref: '#/definitions/PPMDestinationAddress' secondaryDestinationAddress: allOf: - $ref: '#/definitions/Address' @@ -8423,6 +8423,164 @@ definitions: eTag: type: string readOnly: true + PPMDestinationAddress: + description: A postal address + type: object + properties: + id: + type: string + format: uuid + example: c56a4180-65aa-42ec-a945-5fd21dec0538 + streetAddress1: + type: string + example: 123 Main Ave + x-nullable: true + title: Street address 1 + streetAddress2: + type: string + example: Apartment 9000 + x-nullable: true + title: Street address 2 + streetAddress3: + type: string + example: Montmârtre + x-nullable: true + title: Address Line 3 + city: + type: string + example: Anytown + title: City + eTag: + type: string + readOnly: true + state: + title: State + type: string + x-display-value: + AL: AL + AK: AK + AR: AR + AZ: AZ + CA: CA + CO: CO + CT: CT + DC: DC + DE: DE + FL: FL + GA: GA + HI: HI + IA: IA + ID: ID + IL: IL + IN: IN + KS: KS + KY: KY + LA: LA + MA: MA + MD: MD + ME: ME + MI: MI + MN: MN + MO: MO + MS: MS + MT: MT + NC: NC + ND: ND + NE: NE + NH: NH + NJ: NJ + NM: NM + NV: NV + NY: NY + OH: OH + OK: OK + OR: OR + PA: PA + RI: RI + SC: SC + SD: SD + TN: TN + TX: TX + UT: UT + VA: VA + VT: VT + WA: WA + WI: WI + WV: WV + WY: WY + enum: + - AL + - AK + - AR + - AZ + - CA + - CO + - CT + - DC + - DE + - FL + - GA + - HI + - IA + - ID + - IL + - IN + - KS + - KY + - LA + - MA + - MD + - ME + - MI + - MN + - MO + - MS + - MT + - NC + - ND + - NE + - NH + - NJ + - NM + - NV + - NY + - OH + - OK + - OR + - PA + - RI + - SC + - SD + - TN + - TX + - UT + - VA + - VT + - WA + - WI + - WV + - WY + postalCode: + type: string + format: zip + title: ZIP + example: '90210' + pattern: ^(\d{5}([\-]\d{4})?)$ + country: + type: string + title: Country + x-nullable: true + example: USA + default: USA + county: + type: string + title: County + x-nullable: true + example: LOS ANGELES + required: + - city + - state + - postalCode SITLocationType: description: The list of SIT location types. type: string diff --git a/swagger/internal.yaml b/swagger/internal.yaml index edaca330f11..cbfaae155b8 100644 --- a/swagger/internal.yaml +++ b/swagger/internal.yaml @@ -1969,7 +1969,7 @@ definitions: secondaryPickupAddress: $ref: '#/definitions/Address' destinationAddress: - $ref: '#/definitions/Address' + $ref: '#/definitions/PPMDestinationAddress' secondaryDestinationAddress: $ref: '#/definitions/Address' tertiaryDestinationAddress: @@ -2029,7 +2029,7 @@ definitions: pattern: ^(\d{5})$ x-nullable: true destinationAddress: - $ref: '#/definitions/Address' + $ref: '#/definitions/PPMDestinationAddress' secondaryDestinationAddress: $ref: '#/definitions/Address' hasSecondaryDestinationAddress: @@ -3918,6 +3918,164 @@ definitions: RENTAL_EQUIPMENT: Rental equipment TOLLS: Tolls WEIGHING_FEE: Weighing fee + PPMDestinationAddress: + description: A postal address + type: object + properties: + id: + type: string + format: uuid + example: c56a4180-65aa-42ec-a945-5fd21dec0538 + streetAddress1: + type: string + example: 123 Main Ave + x-nullable: true + title: Street address 1 + streetAddress2: + type: string + example: Apartment 9000 + x-nullable: true + title: Street address 2 + streetAddress3: + type: string + example: Montmârtre + x-nullable: true + title: Address Line 3 + city: + type: string + example: Anytown + title: City + eTag: + type: string + readOnly: true + state: + title: State + type: string + x-display-value: + AL: AL + AK: AK + AR: AR + AZ: AZ + CA: CA + CO: CO + CT: CT + DC: DC + DE: DE + FL: FL + GA: GA + HI: HI + IA: IA + ID: ID + IL: IL + IN: IN + KS: KS + KY: KY + LA: LA + MA: MA + MD: MD + ME: ME + MI: MI + MN: MN + MO: MO + MS: MS + MT: MT + NC: NC + ND: ND + NE: NE + NH: NH + NJ: NJ + NM: NM + NV: NV + NY: NY + OH: OH + OK: OK + OR: OR + PA: PA + RI: RI + SC: SC + SD: SD + TN: TN + TX: TX + UT: UT + VA: VA + VT: VT + WA: WA + WI: WI + WV: WV + WY: WY + enum: + - AL + - AK + - AR + - AZ + - CA + - CO + - CT + - DC + - DE + - FL + - GA + - HI + - IA + - ID + - IL + - IN + - KS + - KY + - LA + - MA + - MD + - ME + - MI + - MN + - MO + - MS + - MT + - NC + - ND + - NE + - NH + - NJ + - NM + - NV + - NY + - OH + - OK + - OR + - PA + - RI + - SC + - SD + - TN + - TX + - UT + - VA + - VT + - WA + - WI + - WV + - WY + postalCode: + type: string + format: zip + title: ZIP + example: '90210' + pattern: ^(\d{5}([\-]\d{4})?)$ + country: + type: string + title: Country + x-nullable: true + example: USA + default: USA + county: + type: string + title: County + x-nullable: true + example: LOS ANGELES + required: + - city + - state + - postalCode paths: /feature-flags/user-boolean/{key}: post: diff --git a/swagger/prime_v3.yaml b/swagger/prime_v3.yaml index ad50b524ca3..1e8cdb8578f 100644 --- a/swagger/prime_v3.yaml +++ b/swagger/prime_v3.yaml @@ -729,7 +729,7 @@ definitions: The address of the destination location where goods are being delivered to. allOf: - - $ref: '#/definitions/Address' + - $ref: '#/definitions/PPMDestinationAddress' secondaryDestinationAddress: description: >- An optional secondary address near the destination where goods will be @@ -966,7 +966,7 @@ definitions: The address of the destination location where goods are being delivered to. allOf: - - $ref: '#/definitions/Address' + - $ref: '#/definitions/PPMDestinationAddress' hasSecondaryDestinationAddress: type: boolean x-omitempty: false @@ -2352,6 +2352,164 @@ definitions: - NEEDS_CLOSEOUT - CLOSEOUT_COMPLETE - CANCELED + PPMDestinationAddress: + description: A postal address + type: object + properties: + id: + type: string + format: uuid + example: c56a4180-65aa-42ec-a945-5fd21dec0538 + streetAddress1: + type: string + example: 123 Main Ave + x-nullable: true + title: Street address 1 + streetAddress2: + type: string + example: Apartment 9000 + x-nullable: true + title: Street address 2 + streetAddress3: + type: string + example: Montmârtre + x-nullable: true + title: Address Line 3 + city: + type: string + example: Anytown + title: City + eTag: + type: string + readOnly: true + state: + title: State + type: string + x-display-value: + AL: AL + AK: AK + AR: AR + AZ: AZ + CA: CA + CO: CO + CT: CT + DC: DC + DE: DE + FL: FL + GA: GA + HI: HI + IA: IA + ID: ID + IL: IL + IN: IN + KS: KS + KY: KY + LA: LA + MA: MA + MD: MD + ME: ME + MI: MI + MN: MN + MO: MO + MS: MS + MT: MT + NC: NC + ND: ND + NE: NE + NH: NH + NJ: NJ + NM: NM + NV: NV + NY: NY + OH: OH + OK: OK + OR: OR + PA: PA + RI: RI + SC: SC + SD: SD + TN: TN + TX: TX + UT: UT + VA: VA + VT: VT + WA: WA + WI: WI + WV: WV + WY: WY + enum: + - AL + - AK + - AR + - AZ + - CA + - CO + - CT + - DC + - DE + - FL + - GA + - HI + - IA + - ID + - IL + - IN + - KS + - KY + - LA + - MA + - MD + - ME + - MI + - MN + - MO + - MS + - MT + - NC + - ND + - NE + - NH + - NJ + - NM + - NV + - NY + - OH + - OK + - OR + - PA + - RI + - SC + - SD + - TN + - TX + - UT + - VA + - VT + - WA + - WI + - WV + - WY + postalCode: + type: string + format: zip + title: ZIP + example: '90210' + pattern: ^(\d{5}([\-]\d{4})?)$ + country: + type: string + title: Country + x-nullable: true + example: USA + default: USA + county: + type: string + title: County + x-nullable: true + example: LOS ANGELES + required: + - city + - state + - postalCode SITLocationType: description: The list of SIT location types. type: string @@ -2449,7 +2607,7 @@ definitions: x-nullable: true x-omitempty: false destinationAddress: - $ref: '#/definitions/Address' + $ref: '#/definitions/PPMDestinationAddress' secondaryDestinationAddress: $ref: '#/definitions/Address' hasSecondaryDestinationAddress: