diff --git a/pkg/handlers/ghcapi/queues_test.go b/pkg/handlers/ghcapi/queues_test.go index 90088cf2ec0..d3d39152f8c 100644 --- a/pkg/handlers/ghcapi/queues_test.go +++ b/pkg/handlers/ghcapi/queues_test.go @@ -478,6 +478,11 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerFilters() { Status: models.MTOServiceItemStatusSubmitted, }, }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOFSIT, + }, + }, }, nil) // Service Counseling Completed Move diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index 500cdbad41f..5761af41a01 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -125,8 +125,9 @@ func (f orderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid tooAssignedUserQuery := tooAssignedUserFilter(params.TOOAssignedUser) sortOrderQuery := sortOrder(params.Sort, params.Order, ppmCloseoutGblocs) counselingQuery := counselingOfficeFilter(params.CounselingOffice) + tooDestinationRequestsQuery := tooQueueOriginRequestsFilter(role) // Adding to an array so we can iterate over them and apply the filters after the query structure is set below - options := [20]QueryOption{branchQuery, locatorQuery, dodIDQuery, emplidQuery, customerNameQuery, originDutyLocationQuery, destinationDutyLocationQuery, moveStatusQuery, gblocQuery, submittedAtQuery, appearedInTOOAtQuery, requestedMoveDateQuery, ppmTypeQuery, closeoutInitiatedQuery, closeoutLocationQuery, ppmStatusQuery, sortOrderQuery, scAssignedUserQuery, tooAssignedUserQuery, counselingQuery} + options := [21]QueryOption{branchQuery, locatorQuery, dodIDQuery, emplidQuery, customerNameQuery, originDutyLocationQuery, destinationDutyLocationQuery, moveStatusQuery, gblocQuery, submittedAtQuery, appearedInTOOAtQuery, requestedMoveDateQuery, ppmTypeQuery, closeoutInitiatedQuery, closeoutLocationQuery, ppmStatusQuery, sortOrderQuery, scAssignedUserQuery, tooAssignedUserQuery, counselingQuery, tooDestinationRequestsQuery} var query *pop.Query if ppmCloseoutGblocs { @@ -895,3 +896,95 @@ func sortOrder(sort *string, order *string, ppmCloseoutGblocs bool) QueryOption } } } + +// We want to filter out any moves that have ONLY destination type requests to them, such as destination SIT, shuttle, out of the +// task order queue. If the moves have origin SIT, excess weight risks, or sit extensions with origin SIT service items, they +// should still appear in the task order queue, which is what this query looks for +func tooQueueOriginRequestsFilter(role roles.RoleType) QueryOption { + return func(query *pop.Query) { + if role == roles.RoleTypeTOO { + baseQuery := ` + -- check for moves with destination requests and NOT origin requests, then return the inverse for the TOO queue with the NOT wrapped around the query + NOT ( + -- check for moves with destination requests + ( + -- moves with submitted destination SIT or shuttle submitted service items + EXISTS ( + SELECT 1 + FROM mto_service_items msi + JOIN re_services rs ON msi.re_service_id = rs.id + WHERE msi.mto_shipment_id = mto_shipments.id + AND msi.status = 'SUBMITTED' + AND rs.code IN ('DDFSIT', 'DDASIT', 'DDDSIT', 'DDSHUT', 'DDSFSC', + 'IDFSIT', 'IDASIT', 'IDDSIT', 'IDSHUT', 'IDSFSC') + ) + -- requested shipment address update + OR EXISTS ( + SELECT 1 + FROM shipment_address_updates sau + WHERE sau.shipment_id = mto_shipments.id + AND sau.status = 'REQUESTED' + ) + -- Moves with SIT extensions and ONLY destination SIT service items we filter out of TOO queue + OR ( + EXISTS ( + SELECT 1 + FROM sit_extensions se + JOIN mto_service_items msi ON se.mto_shipment_id = msi.mto_shipment_id + JOIN re_services rs ON msi.re_service_id = rs.id + WHERE se.mto_shipment_id = mto_shipments.id + AND se.status = 'PENDING' + AND rs.code IN ('DDFSIT', 'DDASIT', 'DDDSIT', 'DDSHUT', 'DDSFSC', + 'IDFSIT', 'IDASIT', 'IDDSIT', 'IDSHUT', 'IDSFSC') + ) + -- make sure there are NO origin SIT service items (otherwise, it should be in both queues) + AND NOT EXISTS ( + SELECT 1 + FROM mto_service_items msi + JOIN re_services rs ON msi.re_service_id = rs.id + WHERE msi.mto_shipment_id = mto_shipments.id + AND msi.status = 'SUBMITTED' + AND rs.code IN ('ICRT', 'IUBPK', 'IOFSIT', 'IOASIT', 'IOPSIT', 'IOSHUT', + 'IHUPK', 'IUCRT', 'DCRT', 'MS', 'CS', 'DOFSIT', 'DOASIT', + 'DOPSIT', 'DOSFSC', 'IOSFSC', 'DUPK', 'DUCRT', 'DOSHUT', + 'FSC', 'DMHF', 'DBTF', 'DBHF', 'IBTF', 'IBHF', 'DCRTSA', + 'DLH', 'DOP', 'DPK', 'DSH', 'DNPK', 'INPK', 'UBP', + 'ISLH', 'POEFSC', 'PODFSC', 'IHPK') + ) + ) + ) + -- check for moves with origin requests or conditions where move should appear in TOO queue + AND NOT ( + -- keep moves in the TOO queue with origin submitted service items + EXISTS ( + SELECT 1 + FROM mto_service_items msi + JOIN re_services rs ON msi.re_service_id = rs.id + WHERE msi.mto_shipment_id = mto_shipments.id + AND msi.status = 'SUBMITTED' + AND rs.code IN ('ICRT', 'IUBPK', 'IOFSIT', 'IOASIT', 'IOPSIT', 'IOSHUT', + 'IHUPK', 'IUCRT', 'DCRT', 'MS', 'CS', 'DOFSIT', 'DOASIT', + 'DOPSIT', 'DOSFSC', 'IOSFSC', 'DUPK', 'DUCRT', 'DOSHUT', + 'FSC', 'DMHF', 'DBTF', 'DBHF', 'IBTF', 'IBHF', 'DCRTSA', + 'DLH', 'DOP', 'DPK', 'DSH', 'DNPK', 'INPK', 'UBP', + 'ISLH', 'POEFSC', 'PODFSC', 'IHPK') + ) + -- keep moves in the TOO queue if they have an unacknowledged excess weight risk + OR ( + ( + moves.excess_weight_qualified_at IS NOT NULL + AND moves.excess_weight_acknowledged_at IS NULL + ) + OR ( + moves.excess_unaccompanied_baggage_weight_qualified_at IS NOT NULL + AND moves.excess_unaccompanied_baggage_weight_acknowledged_at IS NULL + ) + ) + ) + ) + + ` + query.Where(baseQuery) + } + } +} diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index 8e0e6eec9e3..9742e038187 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -582,6 +582,724 @@ func (suite *OrderServiceSuite) TestListOrders() { suite.Equal(1, len(moves)) suite.Equal(createdPPM.Shipment.MoveTaskOrder.Locator, moves[0].Locator) }) + + suite.Run("task order queue does not return move with ONLY a destination address update request", func() { + officeUser, _, session := setupTestData() + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + testUUID := uuid.UUID{} + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + { + Model: models.MTOShipment{ + DestinationAddressID: &testUUID, + }, + }, + }, nil) + + suite.NotNil(shipment) + + shipmentAddressUpdate := factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: models.ShipmentAddressUpdate{ + NewAddressID: testUUID, + }, + }, + }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + suite.NotNil(shipmentAddressUpdate) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + // even though 2 moves were created, one by setupTestData(), only one will be returned from the call to List Orders since we filter out + // the one with only a shipment address update to be routed to the destination requests queue + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with origin service items and destination address update request", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only destination shuttle service item + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + originSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOASIT, + }, + }, + }, nil) + suite.NotNil(originSITServiceItem) + + testUUID := uuid.UUID{} + shipmentAddressUpdate := factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: models.ShipmentAddressUpdate{ + NewAddressID: testUUID, + }, + }, + }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + suite.NotNil(shipmentAddressUpdate) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue does not return move with ONLY requested destination SIT service items", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only origin service items + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + originSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOFSIT, + }, + }, + }, nil) + suite.NotNil(originSITServiceItem) + + // build a move with destination service items + move2 := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + shipment2 := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move2, + LinkOnly: true, + }, + }, nil) + + destinationSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + }, nil) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.Equal(models.MTOServiceItemStatusSubmitted, destinationSITServiceItem.Status) + + suite.FatalNoError(err) + // even though 2 moves were created, only one will be returned from the call to List Orders since we filter out + // the one with only destination service items + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with origin requested SIT service items", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only origin service items + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + originSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOFSIT, + }, + }, + }, nil) + suite.NotNil(originSITServiceItem) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with both origin and destination requested SIT service items", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only origin service items + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + originSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOFSIT, + }, + }, + }, nil) + suite.NotNil(originSITServiceItem) + + destinationSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + }, nil) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.Equal(models.MTOServiceItemStatusSubmitted, destinationSITServiceItem.Status) + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with origin shuttle service item", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only origin shuttle service item + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + internationalOriginShuttleServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeIOSHUT, + }, + }, + }, nil) + suite.NotNil(internationalOriginShuttleServiceItem) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue does not return a move with ONLY destination shuttle service item", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only destination shuttle service item + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + domesticDestinationShuttleServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + }, nil) + suite.NotNil(domesticDestinationShuttleServiceItem) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(0, moveCount) + suite.Equal(0, len(moves)) + }) + + suite.Run("task order queue returns a move with both origin and destination shuttle service item", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only destination shuttle service item + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + domesticOriginShuttleServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOSHUT, + }, + }, + }, nil) + suite.NotNil(domesticOriginShuttleServiceItem) + + internationalDestinationShuttleServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeIDSHUT, + }, + }, + }, nil) + suite.NotNil(internationalDestinationShuttleServiceItem) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with excess weight flagged for review", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + now := time.Now() + // build a move with a ExcessWeightQualifiedAt value + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + ExcessWeightQualifiedAt: &now, + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with unaccompanied baggage excess weight flagged for review", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + now := time.Now() + // build a move with a ExcessUnaccompaniedBaggageWeightQualifiedAt value + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + ExcessUnaccompaniedBaggageWeightQualifiedAt: &now, + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue returns a move with a pending SIT extension and origin service items to review", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with origin service items + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + originSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + }, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOFSIT, + }, + }, + }, nil) + suite.NotNil(originSITServiceItem) + sitExtension := factory.BuildSITDurationUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.SITDurationUpdate{ + Status: models.SITExtensionStatusPending, + }, + }, + }, nil) + suite.NotNil(sitExtension) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) + + suite.Run("task order queue does NOT return a move with a pending SIT extension and only destination service items to review", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with destination service items + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + destinationSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + }, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + }, nil) + suite.NotNil(destinationSITServiceItem) + sitExtension := factory.BuildSITDurationUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.SITDurationUpdate{ + Status: models.SITExtensionStatusPending, + }, + }, + }, nil) + suite.NotNil(sitExtension) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.FatalNoError(err) + suite.Equal(0, moveCount) + suite.Equal(0, len(moves)) + }) + + suite.Run("task order queue returns a move with a pending SIT extension and BOTH origin and destination service items to review", func() { + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO}) + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + // build a move with only origin service items + move := factory.BuildMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: move, + LinkOnly: true, + }, + }, nil) + suite.NotNil(shipment) + originSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDOFSIT, + }, + }, + }, nil) + suite.NotNil(originSITServiceItem) + + destinationSITServiceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + }, nil) + + sitExtension := factory.BuildSITDurationUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.SITDurationUpdate{ + Status: models.SITExtensionStatusPending, + }, + }, + }, nil) + suite.NotNil(sitExtension) + + moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}) + + suite.Equal(models.MTOServiceItemStatusSubmitted, destinationSITServiceItem.Status) + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Equal(1, len(moves)) + }) } func (suite *OrderServiceSuite) TestListOrderWithAssignedUserSingle() { // Under test: ListOrders diff --git a/pkg/unit/millicents_test.go b/pkg/unit/millicents_test.go index 0e7056f5f66..d7af7278abe 100644 --- a/pkg/unit/millicents_test.go +++ b/pkg/unit/millicents_test.go @@ -4,6 +4,16 @@ import ( "testing" ) +func TestMillicents_Int64(t *testing.T) { + millicents := Millicents(250000) + result := millicents.Int64() + + expected := int64(250000) + if result != expected { + t.Errorf("wrong number of Millicents: expected %v, got %v", expected, result) + } +} + func TestMillicents_Float64(t *testing.T) { millicents := Millicents(250000) result := millicents.Float64() diff --git a/playwright/tests/office/txo/tooFlows.spec.js b/playwright/tests/office/txo/tooFlows.spec.js index dd85150f3fd..412076deb28 100644 --- a/playwright/tests/office/txo/tooFlows.spec.js +++ b/playwright/tests/office/txo/tooFlows.spec.js @@ -626,17 +626,10 @@ test.describe('TOO user', () => { await page.getByRole('button', { name: 'Select task_ordering_officer' }).click(); }); test('weight-based multiplier prioritizes billed weight', async ({ page }) => { - await page.getByRole('row', { name: 'Select...' }).getByTestId('locator').getByTestId('TextBoxFilter').click(); - await page - .getByRole('row', { name: 'Select...' }) - .getByTestId('locator') - .getByTestId('TextBoxFilter') - .fill(moveLoc); - await page - .getByRole('row', { name: 'Select...' }) - .getByTestId('locator') - .getByTestId('TextBoxFilter') - .press('Enter'); + await page.getByRole('link', { name: 'Search' }).click(); + await page.getByTestId('searchText').click(); + await page.getByTestId('searchText').fill(moveLoc); + await page.getByTestId('searchText').press('Enter'); await page.getByTestId('locator-0').click(); await page.getByRole('link', { name: 'Payment requests' }).click(); await page.getByRole('button', { name: 'Review shipment weights' }).click();