From 7475bf4cf1befb2770542dee51b3969f4590e87a Mon Sep 17 00:00:00 2001 From: Paul Stonebraker Date: Tue, 4 Mar 2025 14:08:47 +0000 Subject: [PATCH] bugfix for ppm shipments failing on counseling office --- pkg/gen/ghcapi/embedded_spec.go | 10 ++++++ pkg/gen/ghcmessages/create_p_p_m_shipment.go | 21 +++++++++++ pkg/handlers/ghcapi/api.go | 1 + pkg/handlers/ghcapi/mto_shipment.go | 19 ++++++++++ pkg/handlers/ghcapi/mto_shipment_test.go | 33 ++++++++++++++++- .../Office/ShipmentForm/ShipmentForm.jsx | 35 +++---------------- src/utils/formatMtoShipment.js | 1 + swagger-def/ghc.yaml | 4 +++ swagger/ghc.yaml | 4 +++ 9 files changed, 96 insertions(+), 32 deletions(-) diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 2b0f92b64a8..5655ed86cd9 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -8080,6 +8080,11 @@ func init() { "hasProGear" ], "properties": { + "closeoutOfficeID": { + "type": "string", + "format": "uuid", + "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" + }, "destinationAddress": { "allOf": [ { @@ -25616,6 +25621,11 @@ func init() { "hasProGear" ], "properties": { + "closeoutOfficeID": { + "type": "string", + "format": "uuid", + "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" + }, "destinationAddress": { "allOf": [ { diff --git a/pkg/gen/ghcmessages/create_p_p_m_shipment.go b/pkg/gen/ghcmessages/create_p_p_m_shipment.go index 87746177f68..ba4ac68c82f 100644 --- a/pkg/gen/ghcmessages/create_p_p_m_shipment.go +++ b/pkg/gen/ghcmessages/create_p_p_m_shipment.go @@ -19,6 +19,11 @@ import ( // swagger:model CreatePPMShipment type CreatePPMShipment struct { + // closeout office ID + // Example: 1f2270c7-7166-40ae-981e-b200ebdf3054 + // Format: uuid + CloseoutOfficeID strfmt.UUID `json:"closeoutOfficeID,omitempty"` + // destination address // Required: true DestinationAddress struct { @@ -113,6 +118,10 @@ type CreatePPMShipment struct { func (m *CreatePPMShipment) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateCloseoutOfficeID(formats); err != nil { + res = append(res, err) + } + if err := m.validateDestinationAddress(formats); err != nil { res = append(res, err) } @@ -171,6 +180,18 @@ func (m *CreatePPMShipment) Validate(formats strfmt.Registry) error { return nil } +func (m *CreatePPMShipment) validateCloseoutOfficeID(formats strfmt.Registry) error { + if swag.IsZero(m.CloseoutOfficeID) { // not required + return nil + } + + if err := validate.FormatOf("closeoutOfficeID", "body", "uuid", m.CloseoutOfficeID.String(), formats); err != nil { + return err + } + + return nil +} + func (m *CreatePPMShipment) validateDestinationAddress(formats strfmt.Registry) error { return nil diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index 4402e196f67..1b69b00086f 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -406,6 +406,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { handlerConfig, shipmentCreator, shipmentSITStatus, + closeoutOfficeUpdater, } ghcAPI.MtoShipmentListMTOShipmentsHandler = ListMTOShipmentsHandler{ diff --git a/pkg/handlers/ghcapi/mto_shipment.go b/pkg/handlers/ghcapi/mto_shipment.go index 1e5453049e7..f63f4440079 100644 --- a/pkg/handlers/ghcapi/mto_shipment.go +++ b/pkg/handlers/ghcapi/mto_shipment.go @@ -206,6 +206,7 @@ type CreateMTOShipmentHandler struct { handlers.HandlerConfig shipmentCreator services.ShipmentCreator shipmentStatus services.ShipmentSITStatus + services.MoveCloseoutOfficeUpdater } // Handle creates the mto shipment @@ -265,6 +266,24 @@ func (h CreateMTOShipmentHandler) Handle(params mtoshipmentops.CreateMTOShipment return handleError(err) } + if payload.PpmShipment != nil && payload.PpmShipment.CloseoutOfficeID != "" { + move, err := models.FetchMoveByMoveID(appCtx.DB(), mtoShipment.MoveTaskOrderID) + if err != nil { + moveFetchError := apperror.NewInternalServerError("Unable to fetch the move associated with this shipment") + appCtx.Logger().Error(moveFetchError.Error()) + return mtoshipmentops.NewCreateMTOShipmentInternalServerError(), moveFetchError + } + + moveEtag := etag.GenerateEtag(move.UpdatedAt) + closeoutOfficeID := uuid.FromStringOrNil(payload.PpmShipment.CloseoutOfficeID.String()) + _, err = h.MoveCloseoutOfficeUpdater.UpdateCloseoutOffice(appCtx, move.Locator, closeoutOfficeID, moveEtag) + if err != nil { + updateCloseoutOfficeError := apperror.NewInternalServerError("Unable to update the move with a closeout office") + appCtx.Logger().Error(updateCloseoutOfficeError.Error()) + return mtoshipmentops.NewCreateMTOShipmentInternalServerError(), updateCloseoutOfficeError + } + } + if mtoShipment == nil { shipmentNotCreatedError := apperror.NewInternalServerError("Unexpected nil shipment from CreateMTOShipment") appCtx.Logger().Error(shipmentNotCreatedError.Error()) diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index 247ef1ae1fb..ef8a07f5b06 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -40,6 +40,7 @@ import ( "github.com/transcom/mymove/pkg/services/query" sitextension "github.com/transcom/mymove/pkg/services/sit_extension" sitstatus "github.com/transcom/mymove/pkg/services/sit_status" + transportationoffice "github.com/transcom/mymove/pkg/services/transportation_office" "github.com/transcom/mymove/pkg/swagger/nullable" "github.com/transcom/mymove/pkg/trace" "github.com/transcom/mymove/pkg/unit" @@ -3683,15 +3684,21 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) sitStatus := sitstatus.NewShipmentSITStatus() + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitStatus, + closeoutOfficeUpdater, } // Validate incoming payload suite.NoError(params.Body.Validate(strfmt.Default)) + fmt.Println("params.Body") + fmt.Println(params.Body) + fmt.Println("params.Body.PpmShipment") + fmt.Println(params.Body.PpmShipment) response := handler.Handle(params) suite.IsType(&mtoshipmentops.CreateMTOShipmentOK{}, response) okResponse := response.(*mtoshipmentops.CreateMTOShipmentOK) @@ -3715,10 +3722,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { shipmentCreator := mocks.ShipmentCreator{} sitStatus := sitstatus.NewShipmentSITStatus() + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, &shipmentCreator, sitStatus, + closeoutOfficeUpdater, } err := errors.New("ServerError") @@ -3767,11 +3776,14 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { moveRouter, setUpSignedCertificationCreatorMock(nil, nil), setUpSignedCertificationUpdaterMock(nil, nil), &ppmEstimator, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) + sitStatus := sitstatus.NewShipmentSITStatus() handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitStatus, + closeoutOfficeUpdater, } badID := params.Body.MoveTaskOrderID @@ -3825,10 +3837,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) sitStatus := sitstatus.NewShipmentSITStatus() + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitStatus, + closeoutOfficeUpdater, } badParams := params @@ -3878,10 +3892,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) sitStatus := sitstatus.NewShipmentSITStatus() + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitStatus, + closeoutOfficeUpdater, } uuidString := "d874d002-5582-4a91-97d3-786e8f66c763" @@ -3926,10 +3942,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) sitStatus := sitstatus.NewShipmentSITStatus() + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitStatus, + closeoutOfficeUpdater, } req := httptest.NewRequest("POST", "/mto-shipments", nil) @@ -4012,10 +4030,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmCreator, boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) sitStatus := sitstatus.NewShipmentSITStatus() + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitStatus, + closeoutOfficeUpdater, } shipmentType := ghcmessages.MTOShipmentTypePPM @@ -4031,7 +4051,13 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { spouseProGearWeight := unit.Pound(200) estimatedIncentive := 654321 sitEstimatedCost := 67500 - + transportationOffice := factory.BuildTransportationOffice(suite.DB(), []factory.Customization{ + { + Model: models.TransportationOffice{ + ProvidesCloseout: true, + }, + }, + }, nil) req := httptest.NewRequest("POST", "/mto-shipments", nil) var pickupAddress ghcmessages.Address @@ -4125,6 +4151,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { HasProGear: &hasProGear, ProGearWeight: handlers.FmtPoundPtr(&proGearWeight), SpouseProGearWeight: handlers.FmtPoundPtr(&spouseProGearWeight), + CloseoutOfficeID: *handlers.FmtUUIDPtr(&transportationOffice.ID), }, }, } @@ -4222,10 +4249,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { moveservices.NewMoveRouter(), setUpSignedCertificationCreatorMock(nil, nil), setUpSignedCertificationUpdaterMock(nil, nil), &ppmEstimator, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmshipment.NewPPMShipmentCreator(&ppmEstimator, addressCreator), boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitstatus.NewShipmentSITStatus(), + closeoutOfficeUpdater, } shipmentType := ghcmessages.MTOShipmentTypePPM @@ -4373,10 +4402,12 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { moveservices.NewMoveRouter(), setUpSignedCertificationCreatorMock(nil, nil), setUpSignedCertificationUpdaterMock(nil, nil), &ppmEstimator, ) shipmentCreator := shipmentorchestrator.NewShipmentCreator(creator, ppmshipment.NewPPMShipmentCreator(&ppmEstimator, addressCreator), boatCreator, mobileHomeCreator, shipmentRouter, moveTaskOrderUpdater) + closeoutOfficeUpdater := moveservices.NewCloseoutOfficeUpdater(moveservices.NewMoveFetcher(), transportationoffice.NewTransportationOfficesFetcher()) handler := CreateMTOShipmentHandler{ handlerConfig, shipmentCreator, sitstatus.NewShipmentSITStatus(), + closeoutOfficeUpdater, } shipmentType := ghcmessages.MTOShipmentTypePPM diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx index 03e7d006b65..dc2264e61b9 100644 --- a/src/components/Office/ShipmentForm/ShipmentForm.jsx +++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx @@ -395,38 +395,11 @@ const ShipmentForm = (props) => { moveCode, shipmentId: newMTOShipment.id, }); - if (formValues.closeoutOffice.id) { - mutateMoveCloseoutOffice( - { - locator: moveCode, - ifMatchETag: move.eTag, - body: { closeoutOfficeId: formValues.closeoutOffice.id }, - }, - { - onSuccess: () => { - actions.setSubmitting(false); - navigate(currentPath, { replace: true }); - if (isTOO) { - navigate(moveViewPath); - } else { - navigate(advancePath); - } - setErrorMessage(null); - onUpdate('success'); - }, - onError: (error) => { - actions.setSubmitting(false); - handleSetError(error, `Something went wrong, and your changes were not saved. Please try again.`); - }, - }, - ); + navigate(currentPath, { replace: true }); + if (isTOO) { + navigate(moveViewPath); } else { - navigate(currentPath, { replace: true }); - if (isTOO) { - navigate(moveViewPath); - } else { - navigate(advancePath); - } + navigate(advancePath); } }, onError: (error) => { diff --git a/src/utils/formatMtoShipment.js b/src/utils/formatMtoShipment.js index 9543a4f4bab..58f0d5a0aef 100644 --- a/src/utils/formatMtoShipment.js +++ b/src/utils/formatMtoShipment.js @@ -307,6 +307,7 @@ export function formatPpmShipmentForAPI(formValues) { hasTertiaryPickupAddress: formValues.hasTertiaryPickup === 'true', hasTertiaryDestinationAddress: formValues.hasTertiaryDestination === 'true', isActualExpenseReimbursement: formValues.isActualExpenseReimbursement === 'true', + closeoutOfficeID: formValues.closeoutOffice.id, }; if (ppmShipmentValues.hasSecondaryPickupAddress) { diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index 96b449bc664..6f105b679fe 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -7144,6 +7144,10 @@ definitions: example: false x-omitempty: false x-nullable: true + closeoutOfficeID: + example: 1f2270c7-7166-40ae-981e-b200ebdf3054 + format: uuid + type: string required: - expectedDepartureDate - pickupAddress diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index 79b22050f44..ed07a78173e 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -7476,6 +7476,10 @@ definitions: example: false x-omitempty: false x-nullable: true + closeoutOfficeID: + example: 1f2270c7-7166-40ae-981e-b200ebdf3054 + format: uuid + type: string required: - expectedDepartureDate - pickupAddress