diff --git a/pkg/gen/primev3api/embedded_spec.go b/pkg/gen/primev3api/embedded_spec.go index ebf4567cbcd..7337ed54033 100644 --- a/pkg/gen/primev3api/embedded_spec.go +++ b/pkg/gen/primev3api/embedded_spec.go @@ -608,8 +608,40 @@ func init() { "format": "date", "x-nullable": true }, + "secondaryDestinationAddress": { + "description": "The second address where the movers should deliver this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, + "secondaryPickupAddress": { + "description": "The second address where the movers should pick up this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, "shipmentType": { "$ref": "#/definitions/MTOShipmentType" + }, + "tertiaryDestinationAddress": { + "description": "The third address where the movers should deliver this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, + "tertiaryPickupAddress": { + "description": "The third address where the movers should pick up this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] } } }, @@ -712,6 +744,22 @@ func init() { "description": "The estimated weight of the pro-gear being moved belonging to a spouse in pounds.", "type": "integer", "x-nullable": true + }, + "tertiaryDestinationAddress": { + "description": "An optional tertiary address near the destination where goods will be dropped off.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, + "tertiaryPickupAddress": { + "description": "An optional tertiary pickup location address near the origin where additional goods exist.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] } } }, @@ -4094,8 +4142,40 @@ func init() { "format": "date", "x-nullable": true }, + "secondaryDestinationAddress": { + "description": "The second address where the movers should deliver this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, + "secondaryPickupAddress": { + "description": "The second address where the movers should pick up this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, "shipmentType": { "$ref": "#/definitions/MTOShipmentType" + }, + "tertiaryDestinationAddress": { + "description": "The third address where the movers should deliver this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, + "tertiaryPickupAddress": { + "description": "The third address where the movers should pick up this shipment.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] } } }, @@ -4198,6 +4278,22 @@ func init() { "description": "The estimated weight of the pro-gear being moved belonging to a spouse in pounds.", "type": "integer", "x-nullable": true + }, + "tertiaryDestinationAddress": { + "description": "An optional tertiary address near the destination where goods will be dropped off.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] + }, + "tertiaryPickupAddress": { + "description": "An optional tertiary pickup location address near the origin where additional goods exist.", + "allOf": [ + { + "$ref": "#/definitions/Address" + } + ] } } }, diff --git a/pkg/gen/primev3messages/create_m_t_o_shipment.go b/pkg/gen/primev3messages/create_m_t_o_shipment.go index fb9de6ba1e7..d25d4962f9c 100644 --- a/pkg/gen/primev3messages/create_m_t_o_shipment.go +++ b/pkg/gen/primev3messages/create_m_t_o_shipment.go @@ -88,9 +88,29 @@ type CreateMTOShipment struct { // Format: date RequestedPickupDate *strfmt.Date `json:"requestedPickupDate,omitempty"` + // The second address where the movers should deliver this shipment. + SecondaryDestinationAddress struct { + Address + } `json:"secondaryDestinationAddress,omitempty"` + + // The second address where the movers should pick up this shipment. + SecondaryPickupAddress struct { + Address + } `json:"secondaryPickupAddress,omitempty"` + // shipment type // Required: true ShipmentType *MTOShipmentType `json:"shipmentType"` + + // The third address where the movers should deliver this shipment. + TertiaryDestinationAddress struct { + Address + } `json:"tertiaryDestinationAddress,omitempty"` + + // The third address where the movers should pick up this shipment. + TertiaryPickupAddress struct { + Address + } `json:"tertiaryPickupAddress,omitempty"` } // MtoServiceItems gets the mto service items of this base type @@ -136,7 +156,23 @@ func (m *CreateMTOShipment) UnmarshalJSON(raw []byte) error { RequestedPickupDate *strfmt.Date `json:"requestedPickupDate,omitempty"` + SecondaryDestinationAddress struct { + Address + } `json:"secondaryDestinationAddress,omitempty"` + + SecondaryPickupAddress struct { + Address + } `json:"secondaryPickupAddress,omitempty"` + ShipmentType *MTOShipmentType `json:"shipmentType"` + + TertiaryDestinationAddress struct { + Address + } `json:"tertiaryDestinationAddress,omitempty"` + + TertiaryPickupAddress struct { + Address + } `json:"tertiaryPickupAddress,omitempty"` } buf := bytes.NewBuffer(raw) dec := json.NewDecoder(buf) @@ -196,9 +232,21 @@ func (m *CreateMTOShipment) UnmarshalJSON(raw []byte) error { // requestedPickupDate result.RequestedPickupDate = data.RequestedPickupDate + // secondaryDestinationAddress + result.SecondaryDestinationAddress = data.SecondaryDestinationAddress + + // secondaryPickupAddress + result.SecondaryPickupAddress = data.SecondaryPickupAddress + // shipmentType result.ShipmentType = data.ShipmentType + // tertiaryDestinationAddress + result.TertiaryDestinationAddress = data.TertiaryDestinationAddress + + // tertiaryPickupAddress + result.TertiaryPickupAddress = data.TertiaryPickupAddress + *m = result return nil @@ -237,7 +285,23 @@ func (m CreateMTOShipment) MarshalJSON() ([]byte, error) { RequestedPickupDate *strfmt.Date `json:"requestedPickupDate,omitempty"` + SecondaryDestinationAddress struct { + Address + } `json:"secondaryDestinationAddress,omitempty"` + + SecondaryPickupAddress struct { + Address + } `json:"secondaryPickupAddress,omitempty"` + ShipmentType *MTOShipmentType `json:"shipmentType"` + + TertiaryDestinationAddress struct { + Address + } `json:"tertiaryDestinationAddress,omitempty"` + + TertiaryPickupAddress struct { + Address + } `json:"tertiaryPickupAddress,omitempty"` }{ Agents: m.Agents, @@ -264,7 +328,15 @@ func (m CreateMTOShipment) MarshalJSON() ([]byte, error) { RequestedPickupDate: m.RequestedPickupDate, + SecondaryDestinationAddress: m.SecondaryDestinationAddress, + + SecondaryPickupAddress: m.SecondaryPickupAddress, + ShipmentType: m.ShipmentType, + + TertiaryDestinationAddress: m.TertiaryDestinationAddress, + + TertiaryPickupAddress: m.TertiaryPickupAddress, }) if err != nil { return nil, err @@ -322,10 +394,26 @@ func (m *CreateMTOShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateSecondaryDestinationAddress(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecondaryPickupAddress(formats); err != nil { + res = append(res, err) + } + if err := m.validateShipmentType(formats); err != nil { res = append(res, err) } + if err := m.validateTertiaryDestinationAddress(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTertiaryPickupAddress(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -454,6 +542,22 @@ func (m *CreateMTOShipment) validateRequestedPickupDate(formats strfmt.Registry) return nil } +func (m *CreateMTOShipment) validateSecondaryDestinationAddress(formats strfmt.Registry) error { + if swag.IsZero(m.SecondaryDestinationAddress) { // not required + return nil + } + + return nil +} + +func (m *CreateMTOShipment) validateSecondaryPickupAddress(formats strfmt.Registry) error { + if swag.IsZero(m.SecondaryPickupAddress) { // not required + return nil + } + + return nil +} + func (m *CreateMTOShipment) validateShipmentType(formats strfmt.Registry) error { if err := validate.Required("shipmentType", "body", m.ShipmentType); err != nil { @@ -478,6 +582,22 @@ func (m *CreateMTOShipment) validateShipmentType(formats strfmt.Registry) error return nil } +func (m *CreateMTOShipment) validateTertiaryDestinationAddress(formats strfmt.Registry) error { + if swag.IsZero(m.TertiaryDestinationAddress) { // not required + return nil + } + + return nil +} + +func (m *CreateMTOShipment) validateTertiaryPickupAddress(formats strfmt.Registry) error { + if swag.IsZero(m.TertiaryPickupAddress) { // not required + return nil + } + + return nil +} + // ContextValidate validate this create m t o shipment based on the context it is used func (m *CreateMTOShipment) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error @@ -502,10 +622,26 @@ func (m *CreateMTOShipment) ContextValidate(ctx context.Context, formats strfmt. res = append(res, err) } + if err := m.contextValidateSecondaryDestinationAddress(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecondaryPickupAddress(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateShipmentType(ctx, formats); err != nil { res = append(res, err) } + if err := m.contextValidateTertiaryDestinationAddress(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTertiaryPickupAddress(ctx, formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -579,6 +715,16 @@ func (m *CreateMTOShipment) contextValidatePpmShipment(ctx context.Context, form return nil } +func (m *CreateMTOShipment) contextValidateSecondaryDestinationAddress(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *CreateMTOShipment) contextValidateSecondaryPickupAddress(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + func (m *CreateMTOShipment) contextValidateShipmentType(ctx context.Context, formats strfmt.Registry) error { if m.ShipmentType != nil { @@ -596,6 +742,16 @@ func (m *CreateMTOShipment) contextValidateShipmentType(ctx context.Context, for return nil } +func (m *CreateMTOShipment) contextValidateTertiaryDestinationAddress(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *CreateMTOShipment) contextValidateTertiaryPickupAddress(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + // MarshalBinary interface implementation func (m *CreateMTOShipment) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/pkg/gen/primev3messages/create_p_p_m_shipment.go b/pkg/gen/primev3messages/create_p_p_m_shipment.go index 6126c4ec5a0..1257b32198a 100644 --- a/pkg/gen/primev3messages/create_p_p_m_shipment.go +++ b/pkg/gen/primev3messages/create_p_p_m_shipment.go @@ -84,6 +84,16 @@ type CreatePPMShipment struct { // The estimated weight of the pro-gear being moved belonging to a spouse in pounds. SpouseProGearWeight *int64 `json:"spouseProGearWeight,omitempty"` + + // An optional tertiary address near the destination where goods will be dropped off. + TertiaryDestinationAddress struct { + Address + } `json:"tertiaryDestinationAddress,omitempty"` + + // An optional tertiary pickup location address near the origin where additional goods exist. + TertiaryPickupAddress struct { + Address + } `json:"tertiaryPickupAddress,omitempty"` } // Validate validates this create p p m shipment @@ -134,6 +144,14 @@ func (m *CreatePPMShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateTertiaryDestinationAddress(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTertiaryPickupAddress(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -249,6 +267,22 @@ func (m *CreatePPMShipment) validateSitLocation(formats strfmt.Registry) error { return nil } +func (m *CreatePPMShipment) validateTertiaryDestinationAddress(formats strfmt.Registry) error { + if swag.IsZero(m.TertiaryDestinationAddress) { // not required + return nil + } + + return nil +} + +func (m *CreatePPMShipment) validateTertiaryPickupAddress(formats strfmt.Registry) error { + if swag.IsZero(m.TertiaryPickupAddress) { // not required + return nil + } + + return nil +} + // ContextValidate validate this create p p m shipment based on the context it is used func (m *CreatePPMShipment) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error @@ -273,6 +307,14 @@ func (m *CreatePPMShipment) ContextValidate(ctx context.Context, formats strfmt. res = append(res, err) } + if err := m.contextValidateTertiaryDestinationAddress(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTertiaryPickupAddress(ctx, formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -320,6 +362,16 @@ func (m *CreatePPMShipment) contextValidateSitLocation(ctx context.Context, form return nil } +func (m *CreatePPMShipment) contextValidateTertiaryDestinationAddress(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *CreatePPMShipment) contextValidateTertiaryPickupAddress(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + // MarshalBinary interface implementation func (m *CreatePPMShipment) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/pkg/handlers/primeapiv3/payloads/payload_to_model.go b/pkg/handlers/primeapiv3/payloads/payload_to_model.go index 50588acfb28..357448d6c27 100644 --- a/pkg/handlers/primeapiv3/payloads/payload_to_model.go +++ b/pkg/handlers/primeapiv3/payloads/payload_to_model.go @@ -166,11 +166,35 @@ func MTOShipmentModelFromCreate(mtoShipment *primev3messages.CreateMTOShipment) model.PickupAddress = addressModel } + addressModel = AddressModel(&mtoShipment.SecondaryPickupAddress.Address) + if addressModel != nil { + model.SecondaryPickupAddress = addressModel + model.HasSecondaryPickupAddress = handlers.FmtBool(true) + } + + addressModel = AddressModel(&mtoShipment.TertiaryPickupAddress.Address) + if addressModel != nil { + model.TertiaryPickupAddress = addressModel + model.HasTertiaryPickupAddress = handlers.FmtBool(true) + } + addressModel = AddressModel(&mtoShipment.DestinationAddress.Address) if addressModel != nil { model.DestinationAddress = addressModel } + addressModel = AddressModel(&mtoShipment.SecondaryDestinationAddress.Address) + if addressModel != nil { + model.SecondaryDeliveryAddress = addressModel + model.HasSecondaryDeliveryAddress = handlers.FmtBool(true) + } + + addressModel = AddressModel(&mtoShipment.TertiaryDestinationAddress.Address) + if addressModel != nil { + model.TertiaryDeliveryAddress = addressModel + model.HasTertiaryDeliveryAddress = handlers.FmtBool(true) + } + if mtoShipment.Agents != nil { model.MTOAgents = *MTOAgentsModel(&mtoShipment.Agents) } @@ -235,6 +259,12 @@ func PPMShipmentModelFromCreate(ppmShipment *primev3messages.CreatePPMShipment) model.HasSecondaryPickupAddress = handlers.FmtBool(true) } + addressModel = AddressModel(&ppmShipment.TertiaryPickupAddress.Address) + if addressModel != nil { + model.TertiaryPickupAddress = addressModel + model.HasTertiaryPickupAddress = handlers.FmtBool(true) + } + addressModel = AddressModel(&ppmShipment.DestinationAddress.Address) if addressModel != nil { model.DestinationAddress = addressModel @@ -246,6 +276,12 @@ func PPMShipmentModelFromCreate(ppmShipment *primev3messages.CreatePPMShipment) model.HasSecondaryDestinationAddress = handlers.FmtBool(true) } + addressModel = AddressModel(&ppmShipment.TertiaryDestinationAddress.Address) + if addressModel != nil { + model.TertiaryDestinationAddress = addressModel + model.HasTertiaryDestinationAddress = handlers.FmtBool(true) + } + if model.SITExpected != nil && *model.SITExpected { if ppmShipment.SitLocation != nil { sitLocation := models.SITLocationType(*ppmShipment.SitLocation) diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx index 476c5232ef4..b16420798cc 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreate.jsx @@ -78,9 +78,7 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { ppmShipment: { expectedDepartureDate, pickupAddress, - secondaryPickupAddress, destinationAddress, - secondaryDestinationAddress, sitExpected, sitLocation, sitEstimatedWeight, @@ -92,9 +90,34 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { spouseProGearWeight, hasSecondaryPickupAddress, hasSecondaryDestinationAddress, + hasTertiaryPickupAddress, + hasTertiaryDestinationAddress, + }, + } = values; + let { + ppmShipment: { + tertiaryPickupAddress, + tertiaryDestinationAddress, + secondaryPickupAddress, + secondaryDestinationAddress, }, } = values; + if (hasSecondaryPickupAddress !== 'true') { + secondaryPickupAddress = {}; + tertiaryPickupAddress = {}; + } + if (hasTertiaryPickupAddress !== 'true') { + tertiaryPickupAddress = {}; + } + if (hasSecondaryDestinationAddress !== 'true') { + secondaryDestinationAddress = {}; + tertiaryDestinationAddress = {}; + } + if (hasTertiaryDestinationAddress !== 'true') { + tertiaryDestinationAddress = {}; + } + body = { moveTaskOrderID: moveCodeOrID, shipmentType, @@ -109,6 +132,12 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { secondaryDestinationAddress: isEmpty(secondaryDestinationAddress) ? null : formatAddressForPrimeAPI(secondaryDestinationAddress), + tertiaryPickupAddress: isEmpty(tertiaryPickupAddress) + ? null + : formatAddressForPrimeAPI(tertiaryPickupAddress), + tertiaryDestinationAddress: isEmpty(tertiaryDestinationAddress) + ? null + : formatAddressForPrimeAPI(tertiaryDestinationAddress), sitExpected, ...(sitExpected && { sitLocation: sitLocation || null, @@ -118,6 +147,8 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { }), hasSecondaryPickupAddress: hasSecondaryPickupAddress === 'true', hasSecondaryDestinationAddress: hasSecondaryDestinationAddress === 'true', + hasTertiaryPickupAddress: hasTertiaryPickupAddress === 'true', + hasTertiaryDestinationAddress: hasTertiaryDestinationAddress === 'true', estimatedWeight: estimatedWeight ? parseInt(estimatedWeight, 10) : null, hasProGear, ...(hasProGear && { @@ -134,8 +165,30 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { destinationAddress, diversion, divertedFromShipmentId, + hasSecondaryPickupAddress, + hasSecondaryDestinationAddress, + hasTertiaryPickupAddress, + hasTertiaryDestinationAddress, } = values; + let { tertiaryPickupAddress, tertiaryDestinationAddress, secondaryPickupAddress, secondaryDestinationAddress } = + values; + + if (hasSecondaryPickupAddress !== 'true') { + secondaryPickupAddress = {}; + tertiaryPickupAddress = {}; + } + if (hasTertiaryPickupAddress !== 'true') { + tertiaryPickupAddress = {}; + } + if (hasSecondaryDestinationAddress !== 'true') { + secondaryDestinationAddress = {}; + tertiaryDestinationAddress = {}; + } + if (hasTertiaryDestinationAddress !== 'true') { + tertiaryDestinationAddress = {}; + } + body = { moveTaskOrderID: moveCodeOrID, shipmentType, @@ -145,6 +198,20 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { destinationAddress: isEmpty(destinationAddress) ? null : formatAddressForPrimeAPI(destinationAddress), diversion: diversion || null, divertedFromShipmentId: divertedFromShipmentId || null, + hasSecondaryPickupAddress: hasSecondaryPickupAddress === 'true', + hasSecondaryDestinationAddress: hasSecondaryDestinationAddress === 'true', + hasTertiaryPickupAddress: hasTertiaryPickupAddress === 'true', + hasTertiaryDestinationAddress: hasTertiaryDestinationAddress === 'true', + secondaryPickupAddress: isEmpty(secondaryPickupAddress) + ? null + : formatAddressForPrimeAPI(secondaryPickupAddress), + secondaryDestinationAddress: isEmpty(secondaryDestinationAddress) + ? null + : formatAddressForPrimeAPI(secondaryDestinationAddress), + tertiaryPickupAddress: isEmpty(tertiaryPickupAddress) ? null : formatAddressForPrimeAPI(tertiaryPickupAddress), + tertiaryDestinationAddress: isEmpty(tertiaryDestinationAddress) + ? null + : formatAddressForPrimeAPI(tertiaryDestinationAddress), }; } @@ -174,6 +241,13 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { state: '', postalCode: '', }, + tertiaryPickupAddress: { + streetAddress1: '', + streetAddress2: '', + city: '', + state: '', + postalCode: '', + }, destinationAddress: { streetAddress1: '', streetAddress2: '', @@ -188,6 +262,13 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { state: '', postalCode: '', }, + tertiaryDestinationAddress: { + streetAddress1: '', + streetAddress2: '', + city: '', + state: '', + postalCode: '', + }, sitExpected: false, sitLocation: '', sitEstimatedWeight: '', @@ -208,6 +289,38 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { destinationAddress: {}, diversion: '', divertedFromShipmentId: '', + secondaryPickupAddress: { + streetAddress1: '', + streetAddress2: '', + city: '', + state: '', + postalCode: '', + }, + tertiaryPickupAddress: { + streetAddress1: '', + streetAddress2: '', + city: '', + state: '', + postalCode: '', + }, + secondaryDestinationAddress: { + streetAddress1: '', + streetAddress2: '', + city: '', + state: '', + postalCode: '', + }, + tertiaryDestinationAddress: { + streetAddress1: '', + streetAddress2: '', + city: '', + state: '', + postalCode: '', + }, + hasSecondaryPickupAddress: 'false', + hasSecondaryDestinationAddress: 'false', + hasTertiaryPickupAddress: 'false', + hasTertiaryDestinationAddress: 'false', }; const validationSchema = Yup.object().shape({ @@ -223,8 +336,10 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { .typeError('Invalid date. Must be in the format: DD MMM YYYY'), pickupAddress: requiredAddressSchema.required('Required'), secondaryPickupAddress: OptionalAddressSchema, + tertiaryPickupAddress: OptionalAddressSchema, destinationAddress: requiredAddressSchema.required('Required'), secondaryDestinationAddress: OptionalAddressSchema, + tertiaryDestinationAddress: OptionalAddressSchema, sitExpected: Yup.boolean().required('Required'), sitLocation: Yup.string().when('sitExpected', { is: true, @@ -269,10 +384,26 @@ const PrimeUIShipmentCreate = ({ setFlashMessage }) => { is: (shipmentType) => shipmentType !== 'PPM', then: () => OptionalAddressSchema, }), + secondaryPickupAddress: Yup.object().when('shipmentType', { + is: (shipmentType) => shipmentType !== 'PPM', + then: () => OptionalAddressSchema, + }), + tertiaryPickupAddress: Yup.object().when('shipmentType', { + is: (shipmentType) => shipmentType !== 'PPM', + then: () => OptionalAddressSchema, + }), destinationAddress: Yup.object().when('shipmentType', { is: (shipmentType) => shipmentType !== 'PPM', then: () => OptionalAddressSchema, }), + secondaryDestinationAddress: Yup.object().when('shipmentType', { + is: (shipmentType) => shipmentType !== 'PPM', + then: () => OptionalAddressSchema, + }), + tertiaryDestinationAddress: Yup.object().when('shipmentType', { + is: (shipmentType) => shipmentType !== 'PPM', + then: () => OptionalAddressSchema, + }), }); return ( diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx index 1cf9263274f..695261c2bd6 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.jsx @@ -18,7 +18,7 @@ const sitLocationOptions = dropdownInputOptions(LOCATION_TYPES); const PrimeUIShipmentCreateForm = () => { const { values } = useFormikContext(); const { shipmentType } = values; - const { sitExpected, hasProGear, hasSecondaryDestinationAddress, hasSecondaryPickupAddress } = values.ppmShipment; + const { sitExpected, hasProGear } = values.ppmShipment; const [, , checkBoxHelperProps] = useField('diversion'); const [, , divertedFromIdHelperProps] = useField('divertedFromShipmentId'); const [isChecked, setIsChecked] = useState(false); @@ -26,6 +26,29 @@ const PrimeUIShipmentCreateForm = () => { const hasShipmentType = !!shipmentType; const isPPM = shipmentType === SHIPMENT_OPTIONS.PPM; + let { + hasSecondaryPickupAddress, + hasSecondaryDestinationAddress, + hasTertiaryPickupAddress, + hasTertiaryDestinationAddress, + } = ''; + + if (isPPM) { + ({ + hasSecondaryPickupAddress, + hasSecondaryDestinationAddress, + hasTertiaryPickupAddress, + hasTertiaryDestinationAddress, + } = values.ppmShipment); + } else { + ({ + hasSecondaryPickupAddress, + hasSecondaryDestinationAddress, + hasTertiaryPickupAddress, + hasTertiaryDestinationAddress, + } = values); + } + // if a shipment is a diversion, then the parent shipment id will be required for input const toggleParentShipmentIdTextBox = (checkboxValue) => { if (checkboxValue) { @@ -101,11 +124,52 @@ const PrimeUIShipmentCreateForm = () => { name="ppmShipment.hasSecondaryPickupAddress" value="false" title="No, there is not a second pickup location" - checked={hasSecondaryPickupAddress !== 'true'} + checked={hasSecondaryPickupAddress !== 'true' && hasTertiaryPickupAddress !== 'true'} /> - {hasSecondaryPickupAddress === 'true' && } + {hasSecondaryPickupAddress === 'true' && ( + <> +
Second Pickup Address
+ + +

Third pickup location

+ +

+ Will the movers pick up any belongings from a third address? (Must be near the pickup address. + Subject to approval.) +

+
+ + +
+
+ + )} + {hasTertiaryPickupAddress === 'true' && hasSecondaryPickupAddress === 'true' && ( + <> +
Third Pickup Address
+ + + )} )} /> @@ -141,12 +205,51 @@ const PrimeUIShipmentCreateForm = () => { name="ppmShipment.hasSecondaryDestinationAddress" value="false" title="No, there is not a second destination location" - checked={hasSecondaryDestinationAddress !== 'true'} + checked={hasSecondaryDestinationAddress !== 'true' && hasTertiaryDestinationAddress !== 'true'} /> {hasSecondaryDestinationAddress === 'true' && ( - + <> +
Second Destination Address
+ + +

Third delivery location

+ +

+ Will the movers pick up any belongings from a third address? (Must be near the pickup address. + Subject to approval.) +

+
+ + +
+
+ + )} + {hasTertiaryDestinationAddress === 'true' && hasSecondaryDestinationAddress === 'true' && ( + <> +
Third Destination Address
+ + )} )} @@ -264,9 +367,168 @@ const PrimeUIShipmentCreateForm = () => {

Shipment Addresses

Pickup Address
- -
Destination Address
- + ( + <> + {fields} +

Second pickup location

+ +

+ Will the movers pick up any belongings from a second address? (Must be near the pickup address. + Subject to approval.) +

+
+ + +
+
+ {hasSecondaryPickupAddress === 'true' && ( + <> +
Second Pickup Address
+ + +

Third pickup location

+ +

+ Will the movers pick up any belongings from a third address? (Must be near the pickup address. + Subject to approval.) +

+
+ + +
+
+ + )} + {hasTertiaryPickupAddress === 'true' && hasSecondaryPickupAddress === 'true' && ( + <> +
Third Pickup Address
+ + + )} + + )} + /> + +

Destination Info

+ ( + <> + {fields} + +

Second delivery location

+ +

+ Will the movers pick up any belongings from a second address? (Must be near the pickup address. + Subject to approval.) +

+
+ + +
+
+ {hasSecondaryDestinationAddress === 'true' && ( + <> +
Second Destination Address
+ + +

Third delivery location

+ +

+ Will the movers pick up any belongings from a third address? (Must be near the pickup address. + Subject to approval.) +

+
+ + +
+
+ + )} + {hasTertiaryDestinationAddress === 'true' && hasSecondaryDestinationAddress === 'true' && ( + <> +
Third Destination Address
+ + + )} + + )} + /> ) )} diff --git a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx index cb384e8d6ae..27cd122c9d7 100644 --- a/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx +++ b/src/pages/PrimeUI/Shipment/PrimeUIShipmentCreateForm.test.jsx @@ -45,8 +45,22 @@ const initialValues = { state: '', streetAddress1: '', }, + tertiaryDeliveryAddress: { + city: '', + postalCode: '', + state: '', + streetAddress1: '', + }, + tertiaryPickupAddress: { + city: '', + postalCode: '', + state: '', + streetAddress1: '', + }, hasSecondaryPickupAddress: 'false', hasSecondaryDestinationAddress: 'false', + hasTertiaryPickupAddress: 'false', + hasTertiaryDestinationAddress: 'false', }, // Other shipment types @@ -54,6 +68,34 @@ const initialValues = { estimatedWeight: '', pickupAddress: {}, destinationAddress: {}, + secondaryDeliveryAddress: { + city: '', + postalCode: '', + state: '', + streetAddress1: '', + }, + secondaryPickupAddress: { + city: '', + postalCode: '', + state: '', + streetAddress1: '', + }, + tertiaryDeliveryAddress: { + city: '', + postalCode: '', + state: '', + streetAddress1: '', + }, + tertiaryPickupAddress: { + city: '', + postalCode: '', + state: '', + streetAddress1: '', + }, + hasSecondaryPickupAddress: 'false', + hasSecondaryDestinationAddress: 'false', + hasTertiaryPickupAddress: 'false', + hasTertiaryDestinationAddress: 'false', diversion: '', divertedFromShipmentId: '', }; @@ -183,6 +225,51 @@ describe('PrimeUIShipmentCreateForm', () => { }, ); + it('renders secondary/tertiary address', async () => { + renderShipmentCreateForm(); + + const shipmentTypeInput = await screen.findByLabelText('Shipment type'); + expect(shipmentTypeInput).toBeInTheDocument(); + + // Select the shipment type + await userEvent.selectOptions(shipmentTypeInput, 'HHG'); + + // Make sure than a PPM-specific field is not visible. + expect(await screen.queryByLabelText('Expected Departure Date')).not.toBeInTheDocument(); + + expect(await screen.findByText('Shipment Dates')).toBeInTheDocument(); + expect(await screen.findByLabelText('Requested pickup')).toHaveValue(initialValues.requestedPickupDate); + + expect(await screen.findByRole('heading', { name: 'Diversion', level: 2 })).toBeInTheDocument(); + expect(await screen.findByLabelText('Diversion')).not.toBeChecked(); + + expect(await screen.findByText('Shipment Weights')).toBeInTheDocument(); + expect(await screen.findByLabelText('Estimated weight (lbs)')).toHaveValue(initialValues.estimatedWeight); + + expect(await screen.findByText('Shipment Addresses')).toBeInTheDocument(); + expect(await screen.findByText('Pickup Address')).toBeInTheDocument(); + expect(screen.getAllByLabelText('Address 1')[0]).toHaveValue(''); + + const hasSecondaryPickup = await screen.findByTestId('has-secondary-pickup'); + await userEvent.click(hasSecondaryPickup); + expect(screen.getAllByLabelText('Address 1')[1]).toHaveValue(''); + + const hasTertiaryPickup = await screen.findByTestId('has-tertiary-pickup'); + await userEvent.click(hasTertiaryPickup); + expect(screen.getAllByLabelText('Address 1')[2]).toHaveValue(''); + + expect(await screen.findByText('Destination Address')).toBeInTheDocument(); + expect(screen.getAllByLabelText('Address 1')[3]).toHaveValue(''); + + const hasSecondaryDestination = await screen.findByTestId('has-secondary-destination'); + await userEvent.click(hasSecondaryDestination); + expect(screen.getAllByLabelText('Address 1')[4]).toHaveValue(''); + + const hasTertiaryDestination = await screen.findByTestId('has-tertiary-destination'); + await userEvent.click(hasTertiaryDestination); + expect(screen.getAllByLabelText('Address 1')[5]).toHaveValue(''); + }); + it('renders the HHG form and displays the shipment id text input when diversion box is checked', async () => { renderShipmentCreateForm(); diff --git a/swagger-def/prime_v3.yaml b/swagger-def/prime_v3.yaml index 9a28d0380e2..f030e1e05a2 100644 --- a/swagger-def/prime_v3.yaml +++ b/swagger-def/prime_v3.yaml @@ -355,6 +355,22 @@ definitions: description: Where the movers should deliver this shipment. allOf: - $ref: 'definitions/Address.yaml' + secondaryPickupAddress: + description: The second address where the movers should pick up this shipment. + allOf: + - $ref: 'definitions/Address.yaml' + tertiaryPickupAddress: + description: The third address where the movers should pick up this shipment. + allOf: + - $ref: 'definitions/Address.yaml' + secondaryDestinationAddress: + description: The second address where the movers should deliver this shipment. + allOf: + - $ref: 'definitions/Address.yaml' + tertiaryDestinationAddress: + description: The third address where the movers should deliver this shipment. + allOf: + - $ref: 'definitions/Address.yaml' shipmentType: $ref: 'definitions/prime/MTOShipmentType.yaml' diversion: @@ -402,6 +418,10 @@ definitions: description: An optional secondary pickup location address near the origin where additional goods exist. allOf: - $ref: 'definitions/Address.yaml' + tertiaryPickupAddress: + description: An optional tertiary pickup location address near the origin where additional goods exist. + allOf: + - $ref: 'definitions/Address.yaml' destinationAddress: description: The address of the destination location where goods are being delivered to. allOf: @@ -410,6 +430,10 @@ definitions: description: An optional secondary address near the destination where goods will be dropped off. allOf: - $ref: 'definitions/Address.yaml' + tertiaryDestinationAddress: + description: An optional tertiary address near the destination where goods will be dropped off. + allOf: + - $ref: 'definitions/Address.yaml' sitExpected: description: | Captures whether some or all of the PPM shipment will require temporary storage at the origin or destination. diff --git a/swagger/prime_v3.yaml b/swagger/prime_v3.yaml index d13c94b496f..8343fccdb4c 100644 --- a/swagger/prime_v3.yaml +++ b/swagger/prime_v3.yaml @@ -627,6 +627,22 @@ definitions: description: Where the movers should deliver this shipment. allOf: - $ref: '#/definitions/Address' + secondaryPickupAddress: + description: The second address where the movers should pick up this shipment. + allOf: + - $ref: '#/definitions/Address' + tertiaryPickupAddress: + description: The third address where the movers should pick up this shipment. + allOf: + - $ref: '#/definitions/Address' + secondaryDestinationAddress: + description: The second address where the movers should deliver this shipment. + allOf: + - $ref: '#/definitions/Address' + tertiaryDestinationAddress: + description: The third address where the movers should deliver this shipment. + allOf: + - $ref: '#/definitions/Address' shipmentType: $ref: '#/definitions/MTOShipmentType' diversion: @@ -682,6 +698,12 @@ definitions: additional goods exist. allOf: - $ref: '#/definitions/Address' + tertiaryPickupAddress: + description: >- + An optional tertiary pickup location address near the origin where + additional goods exist. + allOf: + - $ref: '#/definitions/Address' destinationAddress: description: >- The address of the destination location where goods are being @@ -694,6 +716,12 @@ definitions: dropped off. allOf: - $ref: '#/definitions/Address' + tertiaryDestinationAddress: + description: >- + An optional tertiary address near the destination where goods will be + dropped off. + allOf: + - $ref: '#/definitions/Address' sitExpected: description: > Captures whether some or all of the PPM shipment will require