diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index f041dfee462..d75b98f1ae1 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -10340,6 +10340,15 @@ func init() { "format": "uuid", "x-nullable": true }, + "counselingOffice": { + "$ref": "#/definitions/TransportationOffice" + }, + "counselingOfficeId": { + "description": "The transportation office that will handle services counseling for this move", + "type": "string", + "format": "uuid", + "x-nullable": true + }, "createdAt": { "type": "string", "format": "date-time" @@ -27616,6 +27625,15 @@ func init() { "format": "uuid", "x-nullable": true }, + "counselingOffice": { + "$ref": "#/definitions/TransportationOffice" + }, + "counselingOfficeId": { + "description": "The transportation office that will handle services counseling for this move", + "type": "string", + "format": "uuid", + "x-nullable": true + }, "createdAt": { "type": "string", "format": "date-time" diff --git a/pkg/gen/ghcmessages/move.go b/pkg/gen/ghcmessages/move.go index 26d652a3f42..604dff87fb7 100644 --- a/pkg/gen/ghcmessages/move.go +++ b/pkg/gen/ghcmessages/move.go @@ -61,6 +61,13 @@ type Move struct { // Format: uuid ContractorID *strfmt.UUID `json:"contractorId,omitempty"` + // counseling office + CounselingOffice *TransportationOffice `json:"counselingOffice,omitempty"` + + // The transportation office that will handle services counseling for this move + // Format: uuid + CounselingOfficeID *strfmt.UUID `json:"counselingOfficeId,omitempty"` + // created at // Format: date-time CreatedAt strfmt.DateTime `json:"createdAt,omitempty"` @@ -201,6 +208,14 @@ func (m *Move) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateCounselingOffice(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCounselingOfficeID(formats); err != nil { + res = append(res, err) + } + if err := m.validateCreatedAt(formats); err != nil { res = append(res, err) } @@ -457,6 +472,37 @@ func (m *Move) validateContractorID(formats strfmt.Registry) error { return nil } +func (m *Move) validateCounselingOffice(formats strfmt.Registry) error { + if swag.IsZero(m.CounselingOffice) { // not required + return nil + } + + if m.CounselingOffice != nil { + if err := m.CounselingOffice.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("counselingOffice") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("counselingOffice") + } + return err + } + } + + return nil +} + +func (m *Move) validateCounselingOfficeID(formats strfmt.Registry) error { + if swag.IsZero(m.CounselingOfficeID) { // not required + return nil + } + + if err := validate.FormatOf("counselingOfficeId", "body", "uuid", m.CounselingOfficeID.String(), formats); err != nil { + return err + } + + return nil +} + func (m *Move) validateCreatedAt(formats strfmt.Registry) error { if swag.IsZero(m.CreatedAt) { // not required return nil @@ -701,6 +747,10 @@ func (m *Move) ContextValidate(ctx context.Context, formats strfmt.Registry) err res = append(res, err) } + if err := m.contextValidateCounselingOffice(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateFinancialReviewFlag(ctx, formats); err != nil { res = append(res, err) } @@ -857,6 +907,27 @@ func (m *Move) contextValidateContractor(ctx context.Context, formats strfmt.Reg return nil } +func (m *Move) contextValidateCounselingOffice(ctx context.Context, formats strfmt.Registry) error { + + if m.CounselingOffice != nil { + + if swag.IsZero(m.CounselingOffice) { // not required + return nil + } + + if err := m.CounselingOffice.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("counselingOffice") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("counselingOffice") + } + return err + } + } + + return nil +} + func (m *Move) contextValidateFinancialReviewFlag(ctx context.Context, formats strfmt.Registry) error { if err := validate.ReadOnly(ctx, "financialReviewFlag", "body", bool(m.FinancialReviewFlag)); err != nil { diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go index 882f947c440..6d5feb87bbf 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go @@ -122,6 +122,8 @@ func Move(move *models.Move, storer storage.FileStorer) (*ghcmessages.Move, erro SCAssignedUser: AssignedOfficeUser(move.SCAssignedUser), TOOAssignedUser: AssignedOfficeUser(move.TOOAssignedUser), TIOAssignedUser: AssignedOfficeUser(move.TIOAssignedUser), + CounselingOfficeID: handlers.FmtUUIDPtr(move.CounselingOfficeID), + CounselingOffice: TransportationOffice(move.CounselingOffice), } return payload, nil diff --git a/pkg/handlers/ghcapi/transportation_offices_test.go b/pkg/handlers/ghcapi/transportation_offices_test.go index 087c5c2d243..3be2ce21b3d 100644 --- a/pkg/handlers/ghcapi/transportation_offices_test.go +++ b/pkg/handlers/ghcapi/transportation_offices_test.go @@ -180,7 +180,6 @@ func (suite *HandlerSuite) TestShowCounselingOfficesHandler() { }, }, }, nil) - suite.MustSave(&origDutyLocation) path := fmt.Sprintf("/transportation_offices/%v/counseling_offices", origDutyLocation.ID.String()) req := httptest.NewRequest("GET", path, nil) diff --git a/pkg/handlers/internalapi/transportation_offices_test.go b/pkg/handlers/internalapi/transportation_offices_test.go index b41c5aff7bf..83f875335a4 100644 --- a/pkg/handlers/internalapi/transportation_offices_test.go +++ b/pkg/handlers/internalapi/transportation_offices_test.go @@ -153,7 +153,6 @@ func (suite *HandlerSuite) TestShowCounselingOfficesHandler() { }, }, }, nil) - suite.MustSave(&origDutyLocation) path := fmt.Sprintf("/transportation_offices/%v/counseling_offices", origDutyLocation.ID.String()) req := httptest.NewRequest("GET", path, nil) diff --git a/pkg/services/move/move_fetcher.go b/pkg/services/move/move_fetcher.go index a1ec1d8bbed..23826e321b2 100644 --- a/pkg/services/move/move_fetcher.go +++ b/pkg/services/move/move_fetcher.go @@ -27,7 +27,7 @@ func (f moveFetcher) FetchMove(appCtx appcontext.AppContext, locator string, sea move := &models.Move{} query := appCtx.DB(). EagerPreload("CloseoutOffice.Address", "Contractor", "ShipmentGBLOC", "LockedByOfficeUser", "LockedByOfficeUser.TransportationOffice", "AdditionalDocuments", - "AdditionalDocuments.UserUploads"). + "AdditionalDocuments.UserUploads", "CounselingOffice"). LeftJoin("move_to_gbloc", "move_to_gbloc.move_id = moves.id"). LeftJoin("office_users", "office_users.id = moves.locked_by"). Where("locator = $1", locator) diff --git a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js index 16db36fbc3c..5d8736e16e9 100644 --- a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js +++ b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js @@ -323,6 +323,8 @@ test.describe('Services counselor user', () => { await expect(page.getByText(LocationLookup, { exact: true })).toBeVisible(); await page.keyboard.press('Enter'); await page.locator('select[name="destinationType"]').selectOption({ label: 'Home of selection (HOS)' }); + await page.getByLabel('Requested pickup date').fill('16 Mar 2022'); + await page.locator('[data-testid="submitForm"]').click(); await scPage.waitForLoading(); diff --git a/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx b/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx index c3cc2f27d8b..22df7c03b96 100644 --- a/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx +++ b/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx @@ -429,8 +429,8 @@ describe('AddOrdersForm - With Counseling Office', () => { ); await userEvent.selectOptions(await screen.findByLabelText(/Orders type/), 'PERMANENT_CHANGE_OF_STATION'); - await userEvent.type(screen.getByLabelText(/Orders date/), '08 Nov 2020'); - await userEvent.type(screen.getByLabelText(/Report by date/), '26 Nov 2020'); + await userEvent.paste(screen.getByLabelText(/Orders date/), '08 Nov 2020'); + await userEvent.paste(screen.getByLabelText(/Report by date/), '26 Nov 2020'); await userEvent.click(screen.getByLabelText('No')); await userEvent.selectOptions(screen.getByLabelText(/Pay grade/), ['E_5']); diff --git a/src/components/Office/DefinitionLists/OrdersList.jsx b/src/components/Office/DefinitionLists/OrdersList.jsx index 46ec027d40e..27de47eb1fc 100644 --- a/src/components/Office/DefinitionLists/OrdersList.jsx +++ b/src/components/Office/DefinitionLists/OrdersList.jsx @@ -15,7 +15,7 @@ import { ordersTypeDetailReadable, } from 'utils/formatters'; -const OrdersList = ({ ordersInfo, showMissingWarnings }) => { +const OrdersList = ({ ordersInfo, moveInfo, showMissingWarnings }) => { const { ordersType } = ordersInfo; const isRetiree = ordersType === 'RETIREMENT'; const isSeparatee = ordersType === 'SEPARATION'; @@ -57,6 +57,12 @@ const OrdersList = ({ ordersInfo, showMissingWarnings }) => {
Current duty location
{ordersInfo.currentDutyLocation?.name}
+
+
Counseling office
+
+ {moveInfo?.counselingOffice?.name ? moveInfo.counselingOffice.name : '—'} +
+
{ {isRetiree || isSeparatee ? 'HOR, HOS, or PLEAD' : 'New duty location'}
- {ordersInfo.newDutyLocation?.name ? ordersInfo.newDutyLocation?.name : '-'} + {ordersInfo.newDutyLocation?.name ? ordersInfo.newDutyLocation?.name : '—'}
( NTStac: text('ordersInfo.NTStac', '9999'), payGrade: text('ordersInfo.payGrade', 'E_5'), }} + moveInfo={{ + name: 'PPPO Los Angeles SFB - USAF', + }} />
); @@ -81,6 +84,9 @@ export const AsServiceCounselor = () => ( NTStac: '', payGrade: text('ordersInfo.payGrade', 'E_5'), }} + moveInfo={{ + name: 'PPPO Los Angeles SFB - USAF', + }} /> ); @@ -105,6 +111,9 @@ export const AsServiceCounselorProcessingRetirement = () => ( NTStac: '', payGrade: text('ordersInfo.payGrade', 'E_5'), }} + moveInfo={{ + name: 'PPPO Los Angeles SFB - USAF', + }} /> ); @@ -129,6 +138,9 @@ export const AsServiceCounselorProcessingSeparation = () => ( NTStac: '', payGrade: text('ordersInfo.payGrade', 'E_5'), }} + moveInfo={{ + name: 'PPPO Los Angeles SFB - USAF', + }} /> ); @@ -166,6 +178,9 @@ export const AsTOO = () => ( NTStac: '', payGrade: text('ordersInfo.payGrade', 'E_5'), }} + moveInfo={{ + name: 'PPPO Los Angeles SFB - USAF', + }} /> ); @@ -212,6 +227,9 @@ export const AsTOOProcessingSeparation = () => ( NTStac: '', payGrade: text('ordersInfo.payGrade', 'E_5'), }} + moveInfo={{ + name: 'PPPO Los Angeles SFB - USAF', + }} /> ); diff --git a/src/components/Office/DefinitionLists/OrdersList.test.jsx b/src/components/Office/DefinitionLists/OrdersList.test.jsx index 586c0d1bfab..107463b7a1c 100644 --- a/src/components/Office/DefinitionLists/OrdersList.test.jsx +++ b/src/components/Office/DefinitionLists/OrdersList.test.jsx @@ -32,9 +32,16 @@ const ordersInfo = { payGrade: 'E_7', }; +const moveInfo = { + counselingOffice: { + name: 'PPPO Los Angeles SFB - USAF', + }, +}; + // what ordersInfo from above should be rendered as const expectedRenderedOrdersInfo = { currentDutyLocation: 'JBSA Lackland', + counselingOffice: 'PPPO Los Angeles SFB - USAF', newDutyLocation: 'JB Lewis-McChord', issuedDate: '08 Mar 2020', reportByDate: '01 Apr 2020', @@ -65,7 +72,7 @@ const ordersInfoMissing = { describe('OrdersList', () => { it('renders formatted orders info', () => { - render(); + render(); Object.keys(expectedRenderedOrdersInfo).forEach((key) => { expect(screen.getByText(expectedRenderedOrdersInfo[key])).toBeInTheDocument(); }); diff --git a/src/pages/Office/MoveDetails/MoveDetails.jsx b/src/pages/Office/MoveDetails/MoveDetails.jsx index db24f2ad0e2..1e0ddb8711b 100644 --- a/src/pages/Office/MoveDetails/MoveDetails.jsx +++ b/src/pages/Office/MoveDetails/MoveDetails.jsx @@ -658,7 +658,7 @@ const MoveDetails = ({ } shipmentsInfoNonPpm={shipmentsInfoNonPPM} > - +
diff --git a/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx b/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx index 36e61c24ddf..3d696d8dd7b 100644 --- a/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx +++ b/src/pages/Office/ServicesCounselingMoveDetails/ServicesCounselingMoveDetails.jsx @@ -878,7 +878,7 @@ const ServicesCounselingMoveDetails = ({ } ppmShipmentInfoNeedsApproval={ppmShipmentsInfoNeedsApproval} > - +
diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index 232f3add0f0..78e0c1aee4d 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -5368,6 +5368,13 @@ definitions: format: uuid description: The transportation office that will handle reviewing PPM Closeout documentation for Army and Air Force service members x-nullable: true + counselingOffice: + $ref: 'definitions/TransportationOffice.yaml' + counselingOfficeId: + type: string + format: uuid + description: The transportation office that will handle services counseling for this move + x-nullable: true approvalsRequestedAt: type: string format: date-time diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index 7ffaf58797e..4671262a47a 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -5625,6 +5625,15 @@ definitions: The transportation office that will handle reviewing PPM Closeout documentation for Army and Air Force service members x-nullable: true + counselingOffice: + $ref: '#/definitions/TransportationOffice' + counselingOfficeId: + type: string + format: uuid + description: >- + The transportation office that will handle services counseling for + this move + x-nullable: true approvalsRequestedAt: type: string format: date-time