Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B 22129 closeout data #14539

Merged
merged 13 commits into from
Jan 31, 2025
6 changes: 4 additions & 2 deletions pkg/gen/ghcapi/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/gen/ghcmessages/available_office_user.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions pkg/handlers/ghcapi/queues.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,27 @@ func (h GetBulkAssignmentDataHandler) Handle(
return queues.NewGetBulkAssignmentDataInternalServerError(), err
}

officeUserData = payloads.BulkAssignmentData(appCtx, moves, officeUsers, officeUser.TransportationOffice.ID)
case string(models.QueueTypeCloseout):
// fetch the Services Counselors who work at their office
officeUsers, err := h.OfficeUserFetcherPop.FetchOfficeUsersWithWorkloadByRoleAndOffice(
appCtx,
roles.RoleTypeServicesCounselor,
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.FetchMovesForBulkAssignmentCloseout(
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)
case string(models.QueueTypeTaskOrder):
// fetch the TOOs who work at their office
Expand Down
74 changes: 73 additions & 1 deletion pkg/handlers/ghcapi/queues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1754,7 +1754,6 @@ 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)

Expand Down Expand Up @@ -1820,4 +1819,77 @@ func (suite *HandlerSuite) TestGetBulkAssignmentDataHandler() {
suite.Len(payload.AvailableOfficeUsers, 1)
suite.Len(payload.BulkAssignmentMoveIDs, 1)
})
suite.Run("returns properly formatted closeout 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.RoleTypeServicesCounselor,
},
},
},
},
}, nil)

submittedAt := time.Now()

// move to appear in the return
factory.BuildMoveWithPPMShipment(suite.DB(), []factory.Customization{
{
Model: transportationOffice,
LinkOnly: true,
Type: &factory.TransportationOffices.CloseoutOffice,
},
{
Model: models.PPMShipment{
Status: models.PPMShipmentStatusNeedsCloseout,
SubmittedAt: &submittedAt,
},
},
{
Model: models.Move{
Status: models.MoveStatusAPPROVED,
},
},
}, nil)

request := httptest.NewRequest("GET", "/queues/bulk-assignment", nil)
request = suite.AuthenticateOfficeRequest(request, officeUser)
params := queues.GetBulkAssignmentDataParams{
HTTPRequest: request,
QueueType: models.StringPointer("CLOSEOUT"),
}
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)
})
}
1 change: 1 addition & 0 deletions pkg/services/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type MoveFetcher interface {

type MoveFetcherBulkAssignment interface {
FetchMovesForBulkAssignmentCounseling(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error)
FetchMovesForBulkAssignmentCloseout(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error)
FetchMovesForBulkAssignmentTaskOrder(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error)
}

Expand Down
54 changes: 54 additions & 0 deletions pkg/services/move/move_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,60 @@ func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentCounseling(appCtx
return moves, nil
}

func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentCloseout(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error) {
var moves []models.MoveWithEarliestDate

query := `SELECT
moves.id,
ppm_shipments.submitted_at AS earliest_date
FROM moves
INNER JOIN orders ON orders.id = moves.orders_id
INNER JOIN service_members ON service_members.id = orders.service_member_id
INNER JOIN mto_shipments ON mto_shipments.move_id = moves.id
INNER JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id
WHERE
(moves.status IN ('APPROVED', 'SERVICE COUNSELING COMPLETED'))
AND moves.show = $1
AND moves.sc_assigned_id IS NULL`

switch gbloc {
case "NAVY":
query += ` AND (service_members.affiliation in ('` + string(models.AffiliationNAVY) + `'))`
case "TVCB":
query += ` AND (service_members.affiliation in ('` + string(models.AffiliationMARINES) + `'))`
case "USCG":
query += ` AND (service_members.affiliation in ('` + string(models.AffiliationCOASTGUARD) + `'))`
default:
query += ` AND moves.closeout_office_id = '` + officeId.String() + `'
AND (service_members.affiliation NOT IN ('` +
string(models.AffiliationNAVY) + `', '` +
string(models.AffiliationMARINES) + `', '` +
string(models.AffiliationCOASTGUARD) + `'))`
}

query += ` AND (ppm_shipments.status IN ($2))
AND (orders.orders_type NOT IN ($3, $4, $5))
GROUP BY moves.id, ppm_shipments.submitted_at
ORDER BY earliest_date ASC`

err := appCtx.DB().RawQuery(query,
models.BoolPointer(true),
models.PPMShipmentStatusNeedsCloseout,
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
}

func (f moveFetcherBulkAssignment) FetchMovesForBulkAssignmentTaskOrder(appCtx appcontext.AppContext, gbloc string, officeId uuid.UUID) ([]models.MoveWithEarliestDate, error) {
var moves []models.MoveWithEarliestDate

Expand Down
88 changes: 84 additions & 4 deletions pkg/services/move/move_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,90 @@ func (suite *MoveServiceSuite) TestMoveFetcherBulkAssignment() {
suite.Equal(assignedMove.Orders.OrdersType, internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
})

suite.Run("Closeout returns non Navy/USCG/USMC ppms in needs closeout status", func() {
moveFetcher := NewMoveFetcherBulkAssignment()
transportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil)
officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
{
Model: transportationOffice,
LinkOnly: true,
Type: &factory.TransportationOffices.CloseoutOffice,
},
}, []roles.RoleType{roles.RoleTypeServicesCounselor})

submittedAt := time.Now()

// create non USMC/USCG/NAVY ppm in need closeout status
factory.BuildMoveWithPPMShipment(suite.DB(), []factory.Customization{
{
Model: transportationOffice,
LinkOnly: true,
Type: &factory.TransportationOffices.CloseoutOffice,
},
{
Model: models.PPMShipment{
Status: models.PPMShipmentStatusNeedsCloseout,
SubmittedAt: &submittedAt,
},
},
{
Model: models.Move{
Status: models.MoveStatusAPPROVED,
},
},
}, nil)

// create non closeout needed ppm
factory.BuildMoveWithPPMShipment(suite.DB(), []factory.Customization{
{
Model: transportationOffice,
LinkOnly: true,
Type: &factory.TransportationOffices.CloseoutOffice,
},
{
Model: models.PPMShipment{
Status: models.PPMShipmentStatusWaitingOnCustomer,
SubmittedAt: &submittedAt,
},
},
{
Model: models.Move{
Status: models.MoveStatusAPPROVED,
},
},
}, nil)

marine := models.AffiliationMARINES
marinePPM := factory.BuildPPMShipment(suite.DB(), []factory.Customization{
{
Model: models.Move{
Status: models.MoveStatusAPPROVED,
},
},
{
Model: models.MTOShipment{
ShipmentType: models.MTOShipmentTypePPM,
},
},
{
Model: models.PPMShipment{
Status: models.PPMShipmentStatusNeedsCloseout,
SubmittedAt: &submittedAt,
},
},
{
Model: models.ServiceMember{
Affiliation: &marine,
},
},
}, nil)

moves, err := moveFetcher.FetchMovesForBulkAssignmentCloseout(suite.AppContextForTest(), "KKFA", officeUser.TransportationOffice.ID)
suite.FatalNoError(err)
suite.Equal(1, len(moves))
suite.NotEqual(marinePPM.ID, moves[0].ID)
})

suite.Run("TOO: Returns moves that fulfill the query criteria", func() {
moveFetcher := NewMoveFetcherBulkAssignment()
transportationOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil)
Expand All @@ -444,7 +528,6 @@ func (suite *MoveServiceSuite) TestMoveFetcherBulkAssignment() {
Type: &factory.TransportationOffices.CounselingOffice,
},
}, []roles.RoleType{roles.RoleTypeTOO})

factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{
{
Model: models.Move{
Expand All @@ -457,7 +540,6 @@ func (suite *MoveServiceSuite) TestMoveFetcherBulkAssignment() {
Type: &factory.TransportationOffices.CounselingOffice,
},
}, nil)

factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{
{
Model: models.Move{
Expand All @@ -470,7 +552,6 @@ func (suite *MoveServiceSuite) TestMoveFetcherBulkAssignment() {
Type: &factory.TransportationOffices.CounselingOffice,
},
}, nil)

marine := models.AffiliationMARINES
factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{
{
Expand All @@ -489,7 +570,6 @@ func (suite *MoveServiceSuite) TestMoveFetcherBulkAssignment() {
},
},
}, nil)

moves, err := moveFetcher.FetchMovesForBulkAssignmentTaskOrder(suite.AppContextForTest(), "KKFA", officeUser.TransportationOffice.ID)
suite.FatalNoError(err)
suite.Equal(2, len(moves))
Expand Down
1 change: 1 addition & 0 deletions swagger-def/ghc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7091,6 +7091,7 @@ definitions:
type: boolean
workload:
type: integer
x-omitempty: false
BulkAssignmentData:
type: object
properties:
Expand Down
1 change: 1 addition & 0 deletions swagger/ghc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7440,6 +7440,7 @@ definitions:
type: boolean
workload:
type: integer
x-omitempty: false
BulkAssignmentData:
type: object
properties:
Expand Down
Loading