From f9c214c6b4e431b06041e1e8bc3c21999a08aa2a Mon Sep 17 00:00:00 2001 From: loganwc Date: Mon, 30 Dec 2024 22:05:19 +0000 Subject: [PATCH 1/4] added TOO query and handler for bulk management: --- pkg/handlers/ghcapi/queues.go | 21 +++++++++ pkg/handlers/ghcapi/queues_test.go | 65 ++++++++++++++++++++++++++ pkg/services/move.go | 1 + pkg/services/move/move_fetcher.go | 45 ++++++++++++++++++ pkg/services/move/move_fetcher_test.go | 61 ++++++++++++++++++++++++ 5 files changed, 193 insertions(+) diff --git a/pkg/handlers/ghcapi/queues.go b/pkg/handlers/ghcapi/queues.go index 16c80507c85..ed4980df650 100644 --- a/pkg/handlers/ghcapi/queues.go +++ b/pkg/handlers/ghcapi/queues.go @@ -611,6 +611,27 @@ func (h GetBulkAssignmentDataHandler) Handle( return queues.NewGetBulkAssignmentDataInternalServerError(), err } + officeUserData = payloads.BulkAssignmentData(appCtx, moves, officeUsers, officeUser.TransportationOffice.ID) + case string(models.QueueTypeTaskOrder): + // fetch the TOOs who work at their office + officeUsers, err := h.OfficeUserFetcherPop.FetchOfficeUsersWithWorkloadByRoleAndOffice( + appCtx, + roles.RoleTypeTOO, + officeUser.TransportationOfficeID, + ) + if err != nil { + appCtx.Logger().Error("Error retreiving office users", zap.Error(err)) + return queues.NewGetBulkAssignmentDataInternalServerError(), err + } + // fetch the moves available to be assigned to their office users + moves, err := h.MoveFetcherBulkAssignment.FetchMovesForBulkAssignmentTaskOrder( + appCtx, officeUser.TransportationOffice.Gbloc, officeUser.TransportationOffice.ID, + ) + if err != nil { + appCtx.Logger().Error("Error retreiving moves", zap.Error(err)) + return queues.NewGetBulkAssignmentDataInternalServerError(), err + } + officeUserData = payloads.BulkAssignmentData(appCtx, moves, officeUsers, officeUser.TransportationOffice.ID) } return queues.NewGetBulkAssignmentDataOK().WithPayload(&officeUserData), nil diff --git a/pkg/handlers/ghcapi/queues_test.go b/pkg/handlers/ghcapi/queues_test.go index 8d5c475929f..2ccc4787ccf 100644 --- a/pkg/handlers/ghcapi/queues_test.go +++ b/pkg/handlers/ghcapi/queues_test.go @@ -1742,4 +1742,69 @@ func (suite *HandlerSuite) TestGetBulkAssignmentDataHandler() { suite.Len(payload.AvailableOfficeUsers, 1) suite.Len(payload.BulkAssignmentMoveIDs, 1) }) + suite.Run("TOO: returns properly formatted bulk assignment data", func() { + transportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil) + + officeUser := factory.BuildOfficeUserWithPrivileges(suite.DB(), []factory.Customization{ + { + Model: models.OfficeUser{ + Email: "officeuser1@example.com", + Active: true, + }, + }, + { + Model: transportationOffice, + LinkOnly: true, + Type: &factory.TransportationOffices.CounselingOffice, + }, + { + Model: models.User{ + Privileges: []models.Privilege{ + { + PrivilegeType: models.PrivilegeTypeSupervisor, + }, + }, + Roles: []roles.Role{ + { + RoleType: roles.RoleTypeTOO, + }, + }, + }, + }, + }, nil) + + // move to appear in the return + factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + }, + }, + { + Model: transportationOffice, + LinkOnly: true, + Type: &factory.TransportationOffices.CounselingOffice, + }, + }, nil) + + request := httptest.NewRequest("GET", "/queues/bulk-assignment", nil) + request = suite.AuthenticateOfficeRequest(request, officeUser) + params := queues.GetBulkAssignmentDataParams{ + HTTPRequest: request, + QueueType: models.StringPointer("TASK_ORDER"), + } + handlerConfig := suite.HandlerConfig() + handler := GetBulkAssignmentDataHandler{ + handlerConfig, + officeusercreator.NewOfficeUserFetcherPop(), + movefetcher.NewMoveFetcherBulkAssignment(), + } + response := handler.Handle(params) + suite.IsNotErrResponse(response) + suite.IsType(&queues.GetBulkAssignmentDataOK{}, response) + payload := response.(*queues.GetBulkAssignmentDataOK).Payload + suite.NoError(payload.Validate(strfmt.Default)) + suite.Len(payload.AvailableOfficeUsers, 1) + suite.Len(payload.BulkAssignmentMoveIDs, 1) + }) } diff --git a/pkg/services/move.go b/pkg/services/move.go index 237e360fe3f..8ddda83a8ec 100644 --- a/pkg/services/move.go +++ b/pkg/services/move.go @@ -31,6 +31,7 @@ type MoveFetcher interface { type MoveFetcherBulkAssignment interface { FetchMovesForBulkAssignmentCounseling(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error) + FetchMovesForBulkAssignmentTaskOrder(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error) } //go:generate mockery --name MoveSearcher diff --git a/pkg/services/move/move_fetcher.go b/pkg/services/move/move_fetcher.go index f4fc42dea57..50667430a33 100644 --- a/pkg/services/move/move_fetcher.go +++ b/pkg/services/move/move_fetcher.go @@ -165,3 +165,48 @@ func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentCounseling(appCtx return moves, nil } + +func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentTaskOrder(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error) { + var moves []models.MoveWithEarliestDate + + err := appCtx.DB(). + RawQuery(`SELECT + moves.id, + MIN(LEAST( + COALESCE(mto_shipments.requested_pickup_date, '9999-12-31'), + COALESCE(mto_shipments.requested_delivery_date, '9999-12-31'), + COALESCE(ppm_shipments.expected_departure_date, '9999-12-31') + )) AS earliest_date + FROM moves + INNER JOIN orders ON orders.id = moves.orders_id + INNER JOIN service_members ON orders.service_member_id = service_members.id + INNER JOIN mto_shipments ON mto_shipments.move_id = moves.id + LEFT JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id + WHERE + (moves.status IN ('APPROVALS REQUESTED', 'SUBMITTED', 'SERVICE COUNSELING COMPLETED')) + AND orders.gbloc = $1 + AND moves.show = $2 + AND moves.too_assigned_id IS NULL + AND moves.counseling_transportation_office_id = $3 + AND (orders.orders_type NOT IN ($4, $5, $6)) + AND service_members.affiliation != 'MARINES' + GROUP BY moves.id + ORDER BY earliest_date ASC`, + gbloc, + models.BoolPointer(true), + officeId, + internalmessages.OrdersTypeBLUEBARK, + internalmessages.OrdersTypeWOUNDEDWARRIOR, + internalmessages.OrdersTypeSAFETY). + All(&moves) + + if err != nil { + return nil, fmt.Errorf("error fetching moves for office: %s with error %w", officeId, err) + } + + if len(moves) < 1 { + return nil, nil + } + + return moves, nil +} diff --git a/pkg/services/move/move_fetcher_test.go b/pkg/services/move/move_fetcher_test.go index 381199013cd..92fb23751bb 100644 --- a/pkg/services/move/move_fetcher_test.go +++ b/pkg/services/move/move_fetcher_test.go @@ -433,4 +433,65 @@ func (suite *MoveServiceSuite) TestMoveFetcherBulkAssignment() { // Orders type isn't WW, BB, or Safety suite.Equal(assignedMove.Orders.OrdersType, internalmessages.OrdersTypePERMANENTCHANGEOFSTATION) }) + + suite.Run("TOO: Returns moves that fulfill the query criteria", func() { + moveFetcher := NewMoveFetcherBulkAssignment() + transportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil) + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{ + { + Model: transportationOffice, + LinkOnly: true, + Type: &factory.TransportationOffices.CounselingOffice, + }, + }, []roles.RoleType{roles.RoleTypeTOO}) + + factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + }, + }, + { + Model: transportationOffice, + LinkOnly: true, + Type: &factory.TransportationOffices.CounselingOffice, + }, + }, nil) + + factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusServiceCounselingCompleted, + }, + }, + { + Model: transportationOffice, + LinkOnly: true, + Type: &factory.TransportationOffices.CounselingOffice, + }, + }, nil) + + marine := models.AffiliationMARINES + factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusServiceCounselingCompleted, + }, + }, + { + Model: transportationOffice, + LinkOnly: true, + Type: &factory.TransportationOffices.CounselingOffice, + }, + { + Model: models.ServiceMember{ + Affiliation: &marine, + }, + }, + }, nil) + + moves, err := moveFetcher.FetchMovesForBulkAssignmentTaskOrder(suite.AppContextForTest(), "KKFA", officeUser.TransportationOffice.ID) + suite.FatalNoError(err) + suite.Equal(2, len(moves)) + }) } From 6251f6b5c15ffe2bb6e9cb2c5d060cae58886c44 Mon Sep 17 00:00:00 2001 From: loganwc Date: Fri, 3 Jan 2025 16:46:43 +0000 Subject: [PATCH 2/4] fixed query to meet hidden AC --- pkg/services/move/move_fetcher.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pkg/services/move/move_fetcher.go b/pkg/services/move/move_fetcher.go index 50667430a33..a1ec1d8bbed 100644 --- a/pkg/services/move/move_fetcher.go +++ b/pkg/services/move/move_fetcher.go @@ -182,22 +182,24 @@ func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentTaskOrder(appCtx a INNER JOIN service_members ON orders.service_member_id = service_members.id INNER JOIN mto_shipments ON mto_shipments.move_id = moves.id LEFT JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id + LEFT JOIN move_to_gbloc ON move_to_gbloc.move_id = moves.id WHERE (moves.status IN ('APPROVALS REQUESTED', 'SUBMITTED', 'SERVICE COUNSELING COMPLETED')) - AND orders.gbloc = $1 - AND moves.show = $2 + AND moves.show = $1 AND moves.too_assigned_id IS NULL - AND moves.counseling_transportation_office_id = $3 - AND (orders.orders_type NOT IN ($4, $5, $6)) + AND (orders.orders_type NOT IN ($2, $3, $4)) AND service_members.affiliation != 'MARINES' + AND ((mto_shipments.shipment_type != $5 AND move_to_gbloc.gbloc = $6) OR (mto_shipments.shipment_type = $7 AND orders.gbloc = $8)) GROUP BY moves.id ORDER BY earliest_date ASC`, - gbloc, models.BoolPointer(true), - officeId, internalmessages.OrdersTypeBLUEBARK, internalmessages.OrdersTypeWOUNDEDWARRIOR, - internalmessages.OrdersTypeSAFETY). + internalmessages.OrdersTypeSAFETY, + models.MTOShipmentTypeHHGOutOfNTSDom, + gbloc, + models.MTOShipmentTypeHHGOutOfNTSDom, + gbloc). All(&moves) if err != nil { From fcabbdd76b4e8cdbe1b2cb1cddad26e2ecdbb9ee Mon Sep 17 00:00:00 2001 From: loganwc Date: Tue, 21 Jan 2025 15:56:58 +0000 Subject: [PATCH 3/4] merge conflicts --- pkg/factory/move_factory.go | 8 -------- pkg/models/move.go | 5 ----- 2 files changed, 13 deletions(-) diff --git a/pkg/factory/move_factory.go b/pkg/factory/move_factory.go index 9a81f286cb1..8561df50127 100644 --- a/pkg/factory/move_factory.go +++ b/pkg/factory/move_factory.go @@ -35,14 +35,6 @@ func BuildMove(db *pop.Connection, customs []Customization, traits []Trait) mode closeoutOffice = BuildTransportationOffice(db, tempCloseoutOfficeCustoms, nil) } - var counselingOffice models.TransportationOffice - tempCounselingOfficeCustoms := customs - counselingOfficeResult := findValidCustomization(customs, TransportationOffices.CounselingOffice) - if counselingOfficeResult != nil { - tempCounselingOfficeCustoms = convertCustomizationInList(tempCounselingOfficeCustoms, TransportationOffices.CounselingOffice, TransportationOffice) - counselingOffice = BuildTransportationOffice(db, tempCounselingOfficeCustoms, nil) - } - var scAssignedUser models.OfficeUser tempSCAssignedUserCustoms := customs scAssignedUserResult := findValidCustomization(customs, OfficeUsers.SCAssignedUser) diff --git a/pkg/models/move.go b/pkg/models/move.go index 2c0275c7d69..f0b3ac49269 100644 --- a/pkg/models/move.go +++ b/pkg/models/move.go @@ -110,11 +110,6 @@ type MoveWithEarliestDate struct { EarliestDate time.Time `db:"earliest_date"` } -type MoveWithEarliestDate struct { - ID uuid.UUID `json:"id" db:"id"` - EarliestDate time.Time `db:"earliest_date"` -} - // TableName overrides the table name used by Pop. func (m Move) TableName() string { return "moves" From 99ee650eb7ee8be87acffc71fbec9d25f0ef0a5d Mon Sep 17 00:00:00 2001 From: loganwc Date: Tue, 21 Jan 2025 16:26:39 +0000 Subject: [PATCH 4/4] rename ntsr in move fetcher --- pkg/services/move/move_fetcher.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/services/move/move_fetcher.go b/pkg/services/move/move_fetcher.go index a1ec1d8bbed..f7e0970c656 100644 --- a/pkg/services/move/move_fetcher.go +++ b/pkg/services/move/move_fetcher.go @@ -196,9 +196,9 @@ func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentTaskOrder(appCtx a internalmessages.OrdersTypeBLUEBARK, internalmessages.OrdersTypeWOUNDEDWARRIOR, internalmessages.OrdersTypeSAFETY, - models.MTOShipmentTypeHHGOutOfNTSDom, + models.MTOShipmentTypeHHGOutOfNTS, gbloc, - models.MTOShipmentTypeHHGOutOfNTSDom, + models.MTOShipmentTypeHHGOutOfNTS, gbloc). All(&moves)