From 26f8d3a4dfd19d36e7098123684df1571b511417 Mon Sep 17 00:00:00 2001 From: antgmann Date: Sun, 2 Mar 2025 20:30:46 +0000 Subject: [PATCH 1/4] Feature and testing --- pkg/handlers/ghcapi/mto_shipment_test.go | 58 +++++++++++++++++-- pkg/handlers/primeapiv2/mto_shipment_test.go | 20 ++++++- pkg/handlers/primeapiv3/mto_shipment_test.go | 38 +++++++++++- pkg/services/mocks/MoveTaskOrderUpdater.go | 18 ++++++ pkg/services/move_task_order.go | 1 + .../move_task_order_updater.go | 4 +- .../shipment/shipment_creator.go | 8 +++ .../ppmshipment/ppm_shipment_creator.go | 18 ++++-- .../Office/ShipmentForm/ShipmentForm.jsx | 10 +++- .../ServicesCounselingMoveDetails.jsx | 8 ++- 10 files changed, 167 insertions(+), 16 deletions(-) diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index 247ef1ae1fb..dfc108cac15 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/transcom/mymove/pkg/apperror" + "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/etag" "github.com/transcom/mymove/pkg/factory" mtoshipmentops "github.com/transcom/mymove/pkg/gen/ghcapi/ghcoperations/mto_shipment" @@ -19,7 +20,7 @@ import ( "github.com/transcom/mymove/pkg/gen/ghcmessages" "github.com/transcom/mymove/pkg/handlers" "github.com/transcom/mymove/pkg/models" - "github.com/transcom/mymove/pkg/models/roles" + roles "github.com/transcom/mymove/pkg/models/roles" routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/address" @@ -4103,8 +4104,24 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { StreetAddress3: expectedSecondaryDestinationAddress.StreetAddress3, } + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + ctx := auth.SetSessionInRequestContext(req, session) + params := mtoshipmentops.CreateMTOShipmentParams{ - HTTPRequest: req, + HTTPRequest: req.WithContext(ctx), Body: &ghcmessages.CreateMTOShipment{ MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: &shipmentType, @@ -4144,7 +4161,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { // Validate incoming payload suite.NoError(params.Body.Validate(strfmt.Default)) - response := handler.Handle(params) + response := handler.Handle(params) // NEEDS SESSION suite.IsType(&mtoshipmentops.CreateMTOShipmentOK{}, response) okResponse := response.(*mtoshipmentops.CreateMTOShipmentOK) payload := okResponse.Payload @@ -4271,9 +4288,24 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { } req := httptest.NewRequest("POST", "/mto-shipments", nil) + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + ctx := auth.SetSessionInRequestContext(req, session) params := mtoshipmentops.CreateMTOShipmentParams{ - HTTPRequest: req, + HTTPRequest: req.WithContext(ctx), Body: &ghcmessages.CreateMTOShipment{ MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: &shipmentType, @@ -4423,8 +4455,24 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { req := httptest.NewRequest("POST", "/mto-shipments", nil) + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + ctx := auth.SetSessionInRequestContext(req, session) + params := mtoshipmentops.CreateMTOShipmentParams{ - HTTPRequest: req, + HTTPRequest: req.WithContext(ctx), Body: &ghcmessages.CreateMTOShipment{ MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: &shipmentType, diff --git a/pkg/handlers/primeapiv2/mto_shipment_test.go b/pkg/handlers/primeapiv2/mto_shipment_test.go index 83134e3b522..965050a84af 100644 --- a/pkg/handlers/primeapiv2/mto_shipment_test.go +++ b/pkg/handlers/primeapiv2/mto_shipment_test.go @@ -10,12 +10,14 @@ import ( "github.com/stretchr/testify/mock" "github.com/transcom/mymove/pkg/apperror" + "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/factory" mtoshipmentops "github.com/transcom/mymove/pkg/gen/primev2api/primev2operations/mto_shipment" "github.com/transcom/mymove/pkg/gen/primev2messages" "github.com/transcom/mymove/pkg/handlers" "github.com/transcom/mymove/pkg/handlers/primeapiv2/payloads" "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/models/roles" routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/address" @@ -274,8 +276,24 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { estimatedIncentive := 123456 sitEstimatedCost := 67500 + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + ctx := auth.SetSessionInRequestContext(req, session) + params := mtoshipmentops.CreateMTOShipmentParams{ - HTTPRequest: req, + HTTPRequest: req.WithContext(ctx), Body: &primev2messages.CreateMTOShipment{ MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: primev2messages.NewMTOShipmentType(primev2messages.MTOShipmentTypePPM), diff --git a/pkg/handlers/primeapiv3/mto_shipment_test.go b/pkg/handlers/primeapiv3/mto_shipment_test.go index 085d9eab254..64e09798d5e 100644 --- a/pkg/handlers/primeapiv3/mto_shipment_test.go +++ b/pkg/handlers/primeapiv3/mto_shipment_test.go @@ -13,6 +13,7 @@ import ( "go.uber.org/zap" "github.com/transcom/mymove/pkg/apperror" + "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/etag" "github.com/transcom/mymove/pkg/factory" mtoshipmentops "github.com/transcom/mymove/pkg/gen/primev3api/primev3operations/mto_shipment" @@ -20,6 +21,7 @@ import ( "github.com/transcom/mymove/pkg/handlers" "github.com/transcom/mymove/pkg/handlers/primeapiv3/payloads" "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/models/roles" routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/address" @@ -449,8 +451,24 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { StreetAddress3: expectedTertiaryDestinationAddress.StreetAddress3, } + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + ctx := auth.SetSessionInRequestContext(req, session) + params := mtoshipmentops.CreateMTOShipmentParams{ - HTTPRequest: req, + HTTPRequest: req.WithContext(ctx), Body: &primev3messages.CreateMTOShipment{ MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: primev3messages.NewMTOShipmentType(primev3messages.MTOShipmentTypePPM), @@ -751,8 +769,24 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() { StreetAddress3: addressWithEmptyStreet1.StreetAddress3, } + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + ctx := auth.SetSessionInRequestContext(req, session) + params := mtoshipmentops.CreateMTOShipmentParams{ - HTTPRequest: req, + HTTPRequest: req.WithContext(ctx), Body: &primev3messages.CreateMTOShipment{ MoveTaskOrderID: handlers.FmtUUID(move.ID), ShipmentType: primev3messages.NewMTOShipmentType(primev3messages.MTOShipmentTypePPM), diff --git a/pkg/services/mocks/MoveTaskOrderUpdater.go b/pkg/services/mocks/MoveTaskOrderUpdater.go index ec3a1176939..830c93944ad 100644 --- a/pkg/services/mocks/MoveTaskOrderUpdater.go +++ b/pkg/services/mocks/MoveTaskOrderUpdater.go @@ -113,6 +113,24 @@ func (_m *MoveTaskOrderUpdater) ShowHide(appCtx appcontext.AppContext, moveTaskO return r0, r1 } +// SignCertificationPPMCounselingCompleted provides a mock function with given fields: appCtx, moveID, ppmShipmentID +func (_m *MoveTaskOrderUpdater) SignCertificationPPMCounselingCompleted(appCtx appcontext.AppContext, moveID uuid.UUID, ppmShipmentID uuid.UUID) error { + ret := _m.Called(appCtx, moveID, ppmShipmentID) + + if len(ret) == 0 { + panic("no return value specified for SignCertificationPPMCounselingCompleted") + } + + var r0 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, uuid.UUID, uuid.UUID) error); ok { + r0 = rf(appCtx, moveID, ppmShipmentID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdatePPMType provides a mock function with given fields: appCtx, moveTaskOrderID func (_m *MoveTaskOrderUpdater) UpdatePPMType(appCtx appcontext.AppContext, moveTaskOrderID uuid.UUID) (*models.Move, error) { ret := _m.Called(appCtx, moveTaskOrderID) diff --git a/pkg/services/move_task_order.go b/pkg/services/move_task_order.go index 9f0d3a9f01e..4b0df47add7 100644 --- a/pkg/services/move_task_order.go +++ b/pkg/services/move_task_order.go @@ -65,6 +65,7 @@ type MoveTaskOrderUpdater interface { ShowHide(appCtx appcontext.AppContext, moveTaskOrderID uuid.UUID, show *bool) (*models.Move, error) UpdatePPMType(appCtx appcontext.AppContext, moveTaskOrderID uuid.UUID) (*models.Move, error) MakeAvailableToPrime(appCtx appcontext.AppContext, moveTaskOrderID uuid.UUID) (*models.Move, bool, error) + SignCertificationPPMCounselingCompleted(appCtx appcontext.AppContext, moveID uuid.UUID, ppmShipmentID uuid.UUID) error } // MoveTaskOrderChecker is the service object interface for checking if a MoveTaskOrder is in a certain state diff --git a/pkg/services/move_task_order/move_task_order_updater.go b/pkg/services/move_task_order/move_task_order_updater.go index 463c5e33a37..210d79cdaeb 100644 --- a/pkg/services/move_task_order/move_task_order_updater.go +++ b/pkg/services/move_task_order/move_task_order_updater.go @@ -152,7 +152,7 @@ func (o moveTaskOrderUpdater) UpdateStatusServiceCounselingCompleted(appCtx appc return err } - err = o.signCertificationPPMCounselingCompleted(appCtx, move.ID, move.MTOShipments[i].PPMShipment.ID) + err = o.SignCertificationPPMCounselingCompleted(appCtx, move.ID, move.MTOShipments[i].PPMShipment.ID) if err != nil { return err } @@ -527,7 +527,7 @@ func (o moveTaskOrderUpdater) UpdatePPMType(appCtx appcontext.AppContext, moveTa return updatedMove, nil } -func (o moveTaskOrderUpdater) signCertificationPPMCounselingCompleted(appCtx appcontext.AppContext, moveID uuid.UUID, ppmShipmentID uuid.UUID) error { +func (o moveTaskOrderUpdater) SignCertificationPPMCounselingCompleted(appCtx appcontext.AppContext, moveID uuid.UUID, ppmShipmentID uuid.UUID) error { // Retrieve if PPM has certificate signedCertifications, err := models.FetchSignedCertificationPPMByType(appCtx.DB(), appCtx.Session(), moveID, ppmShipmentID, models.SignedCertificationTypePreCloseoutReviewedPPMPAYMENT) if err != nil { diff --git a/pkg/services/orchestrators/shipment/shipment_creator.go b/pkg/services/orchestrators/shipment/shipment_creator.go index 3690bf71429..9833927df6f 100644 --- a/pkg/services/orchestrators/shipment/shipment_creator.go +++ b/pkg/services/orchestrators/shipment/shipment_creator.go @@ -5,6 +5,7 @@ import ( "github.com/transcom/mymove/pkg/appcontext" "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/services" ) @@ -89,6 +90,13 @@ func (s *shipmentCreator) CreateShipment(appCtx appcontext.AppContext, shipment return err } + if txnAppCtx.Session().Roles.HasRole(roles.RoleTypeServicesCounselor) { + err = s.moveTaskOrderUpdater.SignCertificationPPMCounselingCompleted(txnAppCtx, mtoShipment.MoveTaskOrderID, mtoShipment.PPMShipment.ID) + if err != nil { + return err + } + } + // Update PPMType once shipment gets created. _, err = s.moveTaskOrderUpdater.UpdatePPMType(txnAppCtx, mtoShipment.MoveTaskOrderID) if err != nil { diff --git a/pkg/services/ppmshipment/ppm_shipment_creator.go b/pkg/services/ppmshipment/ppm_shipment_creator.go index 75f8e50f7ae..50e46afa2e9 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator.go @@ -2,12 +2,14 @@ package ppmshipment import ( "fmt" + "time" "github.com/gofrs/uuid" "github.com/transcom/mymove/pkg/appcontext" "github.com/transcom/mymove/pkg/apperror" "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/services" ) @@ -56,6 +58,18 @@ func (f *ppmShipmentCreator) createPPMShipment(appCtx appcontext.AppContext, ppm return apperror.NewInvalidInputError(uuid.Nil, nil, nil, "Must have a DRAFT or SUBMITTED status associated with PPM shipment") } + var mtoShipment models.MTOShipment + if err := txnAppCtx.DB().Find(&mtoShipment, ppmShipment.ShipmentID); err != nil { + return err + } + + if appCtx.Session().Roles.HasRole(roles.RoleTypeServicesCounselor) { + mtoShipment.Status = models.MTOShipmentStatusApproved + ppmShipment.Status = models.PPMShipmentStatusWaitingOnCustomer + now := time.Now() + ppmShipment.ApprovedAt = &now + } + // create pickup and destination addresses if ppmShipment.PickupAddress != nil { address, err = f.addressCreator.CreateAddress(txnAppCtx, ppmShipment.PickupAddress) @@ -165,10 +179,6 @@ func (f *ppmShipmentCreator) createPPMShipment(appCtx appcontext.AppContext, ppm // updating the shipment after PPM creation due to addresses not being created until PPM shipment is created // when populating the market_code column, it is considered domestic if both pickup & dest on the PPM are CONUS addresses - var mtoShipment models.MTOShipment - if err := txnAppCtx.DB().Find(&mtoShipment, ppmShipment.ShipmentID); err != nil { - return err - } if ppmShipment.PickupAddress != nil && ppmShipment.DestinationAddress != nil && ppmShipment.PickupAddress.IsOconus != nil && ppmShipment.DestinationAddress.IsOconus != nil { pickupAddress := ppmShipment.PickupAddress diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx index 076212d6953..f78a889451b 100644 --- a/src/components/Office/ShipmentForm/ShipmentForm.jsx +++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx @@ -871,7 +871,15 @@ const ShipmentForm = (props) => { )} - + {isPPM && !isAdvancePage && isServiceCounselor && ( + + + Warning: Creating a PPM as a Service Counselor will automatically approve the PPM + shipment and send it to the customer. Please ensure all information is correct. After creation you + will not be able to edit the shipment. + + + )} {isUB ? (

diff --git a/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx b/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx index decb6c626d3..5f60086f067 100644 --- a/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx +++ b/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx @@ -291,7 +291,13 @@ const ServicesCounselingMoveDetails = ({ shipmentsInfo = submittedShipmentsNonPPM.map((shipment) => { const editURL = - counselorCanEdit || counselorCanEditNonPPM + // This ternary checks if the shipment is a PPM. If so, PPM Shipments are editable at any time based on their ppm status. + // If the shipment is not a PPM, it uses the existing counselorCanEdit checks for move status + (shipment.shipmentType !== 'PPM' && (counselorCanEdit || counselorCanEditNonPPM)) || + (shipment.shipmentType === 'PPM' && + (shipment.ppmShipment.status === ppmShipmentStatuses.DRAFT || + shipment.ppmShipment.status === ppmShipmentStatuses.SUBMITTED || + shipment.ppmShipment.status === ppmShipmentStatuses.NEEDS_ADVANCE_APPROVAL)) ? `../${generatePath(servicesCounselingRoutes.SHIPMENT_EDIT_PATH, { shipmentId: shipment.id, })}` From 88145ad35bc2e849eb1407ed5644a1983469b152 Mon Sep 17 00:00:00 2001 From: antgmann Date: Sun, 2 Mar 2025 21:48:39 +0000 Subject: [PATCH 2/4] Additional test fixes --- .../shipment/shipment_creator_test.go | 52 +++++++++++++- .../ppmshipment/ppm_shipment_creator_test.go | 70 +++++++++++++++++-- 2 files changed, 115 insertions(+), 7 deletions(-) diff --git a/pkg/services/orchestrators/shipment/shipment_creator_test.go b/pkg/services/orchestrators/shipment/shipment_creator_test.go index b949db757a2..9e79b08ab42 100644 --- a/pkg/services/orchestrators/shipment/shipment_creator_test.go +++ b/pkg/services/orchestrators/shipment/shipment_creator_test.go @@ -8,7 +8,9 @@ import ( "github.com/transcom/mymove/pkg/appcontext" "github.com/transcom/mymove/pkg/apperror" + "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/mocks" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" @@ -174,8 +176,22 @@ func (suite *ShipmentSuite) TestCreateShipment() { suite.Run(fmt.Sprintf("Sets status as expected: %s", name), func() { subtestData := makeSubtestData(false, false) + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } - mtoShipment, err := subtestData.shipmentCreatorOrchestrator.CreateShipment(suite.AppContextForTest(), &tc.shipment) + mtoShipment, err := subtestData.shipmentCreatorOrchestrator.CreateShipment(suite.AppContextWithSessionForTest(session), &tc.shipment) suite.Nil(err) @@ -203,7 +219,22 @@ func (suite *ShipmentSuite) TestCreateShipment() { shipment := shipment suite.Run(fmt.Sprintf("Calls necessary service objects for %s shipments", shipment.ShipmentType), func() { - appCtx := suite.AppContextForTest() + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + + appCtx := suite.AppContextWithSessionForTest(session) subtestData := makeSubtestData(false, false) @@ -252,7 +283,22 @@ func (suite *ShipmentSuite) TestCreateShipment() { PPMShipment: &models.PPMShipment{}, } - mtoShipment, err := subtestData.shipmentCreatorOrchestrator.CreateShipment(suite.AppContextForTest(), shipment) + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + + mtoShipment, err := subtestData.shipmentCreatorOrchestrator.CreateShipment(suite.AppContextWithSessionForTest(session), shipment) suite.NoError(err) diff --git a/pkg/services/ppmshipment/ppm_shipment_creator_test.go b/pkg/services/ppmshipment/ppm_shipment_creator_test.go index 73c545ca608..95e080f9ef0 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator_test.go @@ -7,8 +7,10 @@ import ( "github.com/stretchr/testify/mock" "github.com/transcom/mymove/pkg/apperror" + "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/factory" "github.com/transcom/mymove/pkg/models" + "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/services/address" "github.com/transcom/mymove/pkg/services/mocks" "github.com/transcom/mymove/pkg/testdatagen" @@ -64,7 +66,22 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { // Under test: CreatePPMShipment // Set up: Established valid shipment and valid new PPM shipment // Expected: New PPM shipment successfully created, market code is "d" on the parent shipment - appCtx := suite.AppContextForTest() + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + + appCtx := suite.AppContextWithSessionForTest(session) // Set required fields for PPMShipment subtestData := createSubtestData(models.PPMShipment{ @@ -116,7 +133,22 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { // Under test: CreatePPMShipment // Set up: Established valid shipment and valid new PPM shipment // Expected: New PPM shipment successfully created, market code is "i" on the parent shipment - appCtx := suite.AppContextForTest() + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + + appCtx := suite.AppContextWithSessionForTest(session) // Set required fields for PPMShipment subtestData := createSubtestData(models.PPMShipment{ @@ -213,7 +245,22 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { tt := tt suite.Run(fmt.Sprintf("Returns an InvalidInputError if %s", tt.name), func() { - appCtx := suite.AppContextForTest() + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + + appCtx := suite.AppContextWithSessionForTest(session) subtestData := createSubtestData(tt.ppmShipmentTemplate, tt.mtoShipmentTemplate) @@ -229,7 +276,22 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { } suite.Run("Can successfully create a PPMShipment as SC", func() { - appCtx := suite.AppContextForTest() + // Need a logged in user + lgu := uuid.Must(uuid.NewV4()).String() + user := models.User{ + OktaID: lgu, + OktaEmail: "email@example.com", + } + suite.MustSave(&user) + + session := &auth.Session{ + ApplicationName: auth.OfficeApp, + UserID: user.ID, + IDToken: "fake token", + Roles: roles.Roles{}, + } + + appCtx := suite.AppContextWithSessionForTest(session) // Set required fields for PPMShipment expectedDepartureDate := testdatagen.NextValidMoveDate From a85950b0a85dca9f28aa00e54715b205a8b5a2a9 Mon Sep 17 00:00:00 2001 From: antgmann Date: Mon, 3 Mar 2025 14:34:52 +0000 Subject: [PATCH 3/4] Comment removal and testing --- pkg/handlers/ghcapi/mto_shipment_test.go | 2 +- .../Office/ShipmentForm/ShipmentForm.jsx | 2 +- .../Office/ShipmentForm/ShipmentForm.test.jsx | 10 + .../ServicesCounselingMoveDetails.test.jsx | 278 ++++++++++++++++++ 4 files changed, 290 insertions(+), 2 deletions(-) diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index dfc108cac15..b83610103ff 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -4161,7 +4161,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandlerUsingPPM() { // Validate incoming payload suite.NoError(params.Body.Validate(strfmt.Default)) - response := handler.Handle(params) // NEEDS SESSION + response := handler.Handle(params) suite.IsType(&mtoshipmentops.CreateMTOShipmentOK{}, response) okResponse := response.(*mtoshipmentops.CreateMTOShipmentOK) payload := okResponse.Payload diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx index 8bc6ed8c446..1c96dbb4d89 100644 --- a/src/components/Office/ShipmentForm/ShipmentForm.jsx +++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx @@ -873,7 +873,7 @@ const ShipmentForm = (props) => { {isPPM && !isAdvancePage && isServiceCounselor && ( - + Warning: Creating a PPM as a Service Counselor will automatically approve the PPM shipment and send it to the customer. Please ensure all information is correct. After creation you will not be able to edit the shipment. diff --git a/src/components/Office/ShipmentForm/ShipmentForm.test.jsx b/src/components/Office/ShipmentForm/ShipmentForm.test.jsx index 014110009e8..f4324571f30 100644 --- a/src/components/Office/ShipmentForm/ShipmentForm.test.jsx +++ b/src/components/Office/ShipmentForm/ShipmentForm.test.jsx @@ -2020,6 +2020,16 @@ describe('ShipmentForm component', () => { }); }); + describe('creating a new PPM shipment', () => { + it('renders the PPM shipment form correctly', async () => { + renderWithRouter(); + + expect(await screen.findByTestId('tag')).toHaveTextContent('PPM'); + expect(await screen.findByText('PPM')).toBeInTheDocument(); + expect(await screen.findByTestId('scPPMCreateWarning')).toBeInTheDocument(); + }); + }); + describe('creating a new Boat shipment', () => { it('renders the Boat shipment form correctly', async () => { renderWithRouter(); diff --git a/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.test.jsx b/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.test.jsx index 8f125ec8ae5..851ea52c979 100644 --- a/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.test.jsx +++ b/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.test.jsx @@ -638,6 +638,255 @@ const ppmShipmentQuery = { ], }; +const ppmShipmentQueryNoHHG = { + ...newMoveDetailsQuery, + mtoShipments: [ + { + customerRemarks: 'Please treat gently', + eTag: 'MjAyMi0xMS0wOFQyMzo0NDo1OC4yMTc4MVo=', + id: '167985a7-6d47-4412-b620-d4b7f98a09ed', + moveTaskOrderID: 'ddf94b4f-db77-4916-83ff-0d6bc68c8b42', + ppmShipment: { + actualDestinationPostalCode: null, + actualMoveDate: null, + actualPickupPostalCode: null, + advanceAmountReceived: null, + advanceAmountRequested: 598700, + approvedAt: null, + createdAt: '2022-11-08T23:44:58.226Z', + eTag: 'MjAyMi0xMS0wOFQyMzo0NDo1OC4yMjY0NTNa', + estimatedIncentive: 1000000, + estimatedWeight: 4000, + expectedDepartureDate: '2020-03-15', + finalIncentive: null, + hasProGear: true, + hasReceivedAdvance: null, + hasRequestedAdvance: true, + id: '79b98a71-158d-4b04-9a6c-25543c52183d', + movingExpenses: null, + proGearWeight: 1987, + proGearWeightTickets: null, + reviewedAt: null, + hasSecondaryPickupAddress: true, + hasSecondaryDestinationAddress: true, + pickupAddress: { + streetAddress1: '111 Test Street', + streetAddress2: '222 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42701', + }, + secondaryPickupAddress: { + streetAddress1: '777 Test Street', + streetAddress2: '888 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42702', + }, + destinationAddress: { + streetAddress1: '222 Test Street', + streetAddress2: '333 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42703', + }, + secondaryDestinationAddress: { + streetAddress1: '444 Test Street', + streetAddress2: '555 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42701', + }, + shipmentId: '167985a7-6d47-4412-b620-d4b7f98a09ed', + sitEstimatedCost: null, + sitEstimatedDepartureDate: null, + sitEstimatedEntryDate: null, + sitEstimatedWeight: null, + sitExpected: false, + spouseProGearWeight: 498, + status: 'NEEDS_CLOSEOUT', + submittedAt: null, + updatedAt: '2022-11-08T23:44:58.226Z', + weightTickets: [{ emptyWeight: 0, fullWeight: 20000 }], + }, + primeActualWeight: 980, + requestedDeliveryDate: '0001-01-01', + requestedPickupDate: '0001-01-01', + shipmentType: 'PPM', + status: 'APPROVED', + updatedAt: '2022-11-08T23:44:58.217Z', + }, + { + customerRemarks: 'Please treat gently', + eTag: 'MjAyMi0xMS0wOFQyMzo0NDo1OC4yMTc4MVo=', + id: 'e33a1a7b-530f-4df4-b947-d3d719786385', + moveTaskOrderID: 'ddf94b4f-db77-4916-83ff-0d6bc68c8b42', + ppmShipment: { + actualDestinationPostalCode: null, + actualMoveDate: null, + actualPickupPostalCode: null, + advanceAmountReceived: null, + advanceAmountRequested: 598700, + approvedAt: null, + createdAt: '2022-11-08T23:44:58.226Z', + eTag: 'MjAyMi0xMS0wOFQyMzo0NDo1OC4yMjY0NTNa', + estimatedIncentive: 1000000, + estimatedWeight: 4000, + expectedDepartureDate: '2020-03-15', + finalIncentive: null, + hasProGear: true, + hasReceivedAdvance: null, + hasRequestedAdvance: true, + id: '79b98a71-158d-4b04-9a6c-25543c52183d', + movingExpenses: null, + hasSecondaryPickupAddress: true, + hasSecondaryDestinationAddress: true, + pickupAddress: { + streetAddress1: '111 Test Street', + streetAddress2: '222 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42701', + }, + secondaryPickupAddress: { + streetAddress1: '777 Test Street', + streetAddress2: '888 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42702', + }, + destinationAddress: { + streetAddress1: '222 Test Street', + streetAddress2: '333 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42703', + }, + secondaryDestinationAddress: { + streetAddress1: '444 Test Street', + streetAddress2: '555 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42701', + }, + proGearWeight: 1987, + proGearWeightTickets: null, + reviewedAt: null, + shipmentId: 'e33a1a7b-530f-4df4-b947-d3d719786385', + sitEstimatedCost: null, + sitEstimatedDepartureDate: null, + sitEstimatedEntryDate: null, + sitEstimatedWeight: null, + sitExpected: false, + spouseProGearWeight: 498, + status: 'NEEDS_CLOSEOUT', + submittedAt: null, + updatedAt: '2022-11-08T23:44:58.226Z', + weightTickets: null, + }, + primeActualWeight: 980, + requestedDeliveryDate: '0001-01-01', + requestedPickupDate: '0001-01-01', + shipmentType: 'PPM', + status: 'APPROVED', + updatedAt: '2022-11-08T23:44:58.217Z', + }, + ], +}; + +const submittedPPMShipmentQuery = { + ...newMoveDetailsQuery, + mtoShipments: [ + { + customerRemarks: 'Please treat gently', + eTag: 'MjAyMi0xMS0wOFQyMzo0NDo1OC4yMTc4MVo=', + id: '167985a7-6d47-4412-b620-d4b7f98a09ed', + moveTaskOrderID: 'ddf94b4f-db77-4916-83ff-0d6bc68c8b42', + ppmShipment: { + actualDestinationPostalCode: null, + actualMoveDate: null, + actualPickupPostalCode: null, + advanceAmountReceived: null, + advanceAmountRequested: 598700, + approvedAt: null, + createdAt: '2022-11-08T23:44:58.226Z', + eTag: 'MjAyMi0xMS0wOFQyMzo0NDo1OC4yMjY0NTNa', + estimatedIncentive: 1000000, + estimatedWeight: 4000, + expectedDepartureDate: '2020-03-15', + finalIncentive: null, + hasProGear: true, + hasReceivedAdvance: null, + hasRequestedAdvance: true, + id: '79b98a71-158d-4b04-9a6c-25543c52183d', + movingExpenses: null, + proGearWeight: 1987, + proGearWeightTickets: null, + reviewedAt: null, + hasSecondaryPickupAddress: true, + hasSecondaryDestinationAddress: true, + pickupAddress: { + streetAddress1: '111 Test Street', + streetAddress2: '222 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42701', + }, + secondaryPickupAddress: { + streetAddress1: '777 Test Street', + streetAddress2: '888 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42702', + }, + destinationAddress: { + streetAddress1: '222 Test Street', + streetAddress2: '333 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42703', + }, + secondaryDestinationAddress: { + streetAddress1: '444 Test Street', + streetAddress2: '555 Test Street', + streetAddress3: 'Test Man', + city: 'Test City', + state: 'KY', + postalCode: '42701', + }, + shipmentId: '167985a7-6d47-4412-b620-d4b7f98a09ed', + sitEstimatedCost: null, + sitEstimatedDepartureDate: null, + sitEstimatedEntryDate: null, + sitEstimatedWeight: null, + sitExpected: false, + spouseProGearWeight: 498, + status: 'SUBMITTED', + submittedAt: null, + updatedAt: '2022-11-08T23:44:58.226Z', + weightTickets: [{ emptyWeight: 0, fullWeight: 20000 }], + }, + primeActualWeight: 980, + requestedDeliveryDate: '0001-01-01', + requestedPickupDate: '0001-01-01', + shipmentType: 'PPM', + status: 'SUBMITTED', + updatedAt: '2022-11-08T23:44:58.217Z', + }, + ], +}; + const renderComponent = (props, permissions = [permissionTypes.updateShipment, permissionTypes.updateCustomer]) => { return render( @@ -1181,6 +1430,35 @@ describe('MoveDetails page', () => { }); }); + describe('ppm specific statuses for service counselor', () => { + // PPM Shipments should show the edit button on shipments where PPM Shipment status is DRAFT, SUBMITTED, or NEEDS_ADVANCE_APPROVAL + it('hides submit and view/edit buttons/links for statuses it should', async () => { + useMoveDetailsQueries.mockReturnValue(ppmShipmentQueryNoHHG); + + renderComponent(); + + expect(screen.queryByRole('button', { name: 'Submit move details' })).not.toBeInTheDocument(); + expect(screen.queryByRole('combobox')).toBeInTheDocument(); // Add a new shipment ButtonDropdown + expect(screen.queryByRole('button', { name: 'Edit shipment' })).not.toBeInTheDocument(); + expect(screen.queryByRole('link', { name: 'View and edit orders' })).toBeInTheDocument(); + expect(screen.queryByRole('link', { name: 'Edit allowances' })).toBeInTheDocument(); + expect(screen.queryByRole('link', { name: 'Edit customer info' })).toBeInTheDocument(); + }); + + it('shows submit and view/edit buttons/links for statuses it should', async () => { + useMoveDetailsQueries.mockReturnValue(submittedPPMShipmentQuery); + + renderComponent(); + + expect(screen.queryByRole('button', { name: 'Submit move details' })).toBeInTheDocument(); + expect(screen.queryByRole('combobox')).toBeInTheDocument(); // Add a new shipment ButtonDropdown + expect(screen.queryByRole('button', { name: 'Edit shipment' })).toBeInTheDocument(); + expect(screen.queryByRole('link', { name: 'View and edit orders' })).toBeInTheDocument(); + expect(screen.queryByRole('link', { name: 'Edit allowances' })).toBeInTheDocument(); + expect(screen.queryByRole('link', { name: 'Edit customer info' })).toBeInTheDocument(); + }); + }); + describe('permission dependent rendering', () => { useMoveDetailsQueries.mockReturnValue(newMoveDetailsQuery); From 85ef24b4d9ef7266f059714ee038998676b101e0 Mon Sep 17 00:00:00 2001 From: antgmann Date: Mon, 3 Mar 2025 14:49:41 +0000 Subject: [PATCH 4/4] Backend PPM test --- .../ppmshipment/ppm_shipment_creator_test.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pkg/services/ppmshipment/ppm_shipment_creator_test.go b/pkg/services/ppmshipment/ppm_shipment_creator_test.go index 95e080f9ef0..dcbad6bb7a7 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator_test.go @@ -277,19 +277,16 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { suite.Run("Can successfully create a PPMShipment as SC", func() { // Need a logged in user - lgu := uuid.Must(uuid.NewV4()).String() - user := models.User{ - OktaID: lgu, - OktaEmail: "email@example.com", - } - suite.MustSave(&user) + scOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeServicesCounselor}) + identity, err := models.FetchUserIdentity(suite.DB(), scOfficeUser.User.OktaID) + suite.NoError(err) session := &auth.Session{ ApplicationName: auth.OfficeApp, - UserID: user.ID, + UserID: *scOfficeUser.UserID, IDToken: "fake token", - Roles: roles.Roles{}, } + session.Roles = append(session.Roles, identity.Roles...) appCtx := suite.AppContextWithSessionForTest(session) @@ -380,7 +377,7 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { suite.Equal(&sitExpected, createdPPMShipment.SITExpected) suite.Equal(&estimatedWeight, createdPPMShipment.EstimatedWeight) suite.Equal(&hasProGear, createdPPMShipment.HasProGear) - suite.Equal(models.PPMShipmentStatusSubmitted, createdPPMShipment.Status) + suite.Equal(models.PPMShipmentStatusWaitingOnCustomer, createdPPMShipment.Status) suite.Equal(&estimatedIncentive, createdPPMShipment.EstimatedIncentive) suite.Equal(&maxIncentive, createdPPMShipment.MaxIncentive) suite.NotZero(createdPPMShipment.CreatedAt)