From 1f0d1a254a0f15a2e2879af95c8d33d5d6ba4067 Mon Sep 17 00:00:00 2001
From: joeydoyecaci
Date: Tue, 4 Feb 2025 21:06:56 +0000
Subject: [PATCH 01/36] fixed error modal mailto Link
---
src/shared/ErrorModal/ErrorModal.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/ErrorModal/ErrorModal.jsx b/src/shared/ErrorModal/ErrorModal.jsx
index cf6f28794aa..b5533a20c58 100644
--- a/src/shared/ErrorModal/ErrorModal.jsx
+++ b/src/shared/ErrorModal/ErrorModal.jsx
@@ -12,7 +12,7 @@ export const ErrorModal = ({ closeModal, errorMessage, displayHelpDeskLink = tru
{errorMessage}
{displayHelpDeskLink && (
- Technical Help Desk
+ Technical Help Desk
)}
From f3eee7b0b1a8b314b9214f22d65b8c11a32e5a34 Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Tue, 4 Feb 2025 22:50:23 +0000
Subject: [PATCH 02/36] third addres on
---
.envrc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.envrc b/.envrc
index c5e72d09ad2..a33401c69de 100644
--- a/.envrc
+++ b/.envrc
@@ -137,7 +137,7 @@ export FEATURE_FLAG_SAFETY_MOVE=true
export FEATURE_FLAG_MANAGE_SUPPORTING_DOCS=true
# Feature flags to enable third address
-export FEATURE_FLAG_THIRD_ADDRESS_AVAILABLE=false
+export FEATURE_FLAG_THIRD_ADDRESS_AVAILABLE=true
# Feature flag to disable/enable headquarters role
export FEATURE_FLAG_HEADQUARTERS_ROLE=true
From 26923c6cf0ab2de69060da2ec166a0dc8b550377 Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Tue, 4 Feb 2025 23:57:57 +0000
Subject: [PATCH 03/36] Initial checks for empty second address
---
.../Office/ShipmentForm/ShipmentForm.jsx | 25 ++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx
index 076212d6953..08e9e4fdc53 100644
--- a/src/components/Office/ShipmentForm/ShipmentForm.jsx
+++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx
@@ -357,6 +357,29 @@ const ShipmentForm = (props) => {
: generatePath(servicesCounselingRoutes.BASE_ORDERS_EDIT_PATH, { moveCode });
const submitMTOShipment = (formValues, actions) => {
+ if (formValues.hasTertiaryDestination === 'true' && formValues.secondaryDestination.address.streetAddress1 === '') {
+ actions.setFieldError('secondaryDestination.address.streetAddress1', 'destination address required');
+ actions.setSubmitting(false);
+ return;
+ }
+ if (formValues.hasTertiaryPickup === 'true' && formValues.secondaryPickup.address.streetAddress1 === '') {
+ actions.setFieldError('secondaryPickup.address.streetAddress1', 'Pickup address required');
+ actions.setSubmitting(false);
+ return;
+ }
+
+ if (formValues.hasTertiaryDelivery === 'yes' && formValues.secondaryDelivery.address.streetAddress1 === '') {
+ actions.setFieldError('secondaryDelivery.address.streetAddress1', 'destination address required');
+ actions.setSubmitting(false);
+ return;
+ }
+
+ if (formValues.hasTertiaryPickup === 'yes' && formValues.secondaryPickup.address.streetAddress1 === '') {
+ actions.setFieldError('secondaryPickup.address.streetAddress1', 'Pickup address required');
+ actions.setSubmitting(false);
+ return;
+ }
+
//* PPM Shipment *//
if (isPPM) {
const ppmShipmentBody = formatPpmShipmentForAPI(formValues);
@@ -1496,7 +1519,7 @@ const ShipmentForm = (props) => {
name="hasTertiaryPickup"
value="false"
title="No, there is not a third pickup address"
- checked={hasTertiaryPickup !== 'true'}
+ checked={hasTertiaryPickup !== 'yes'}
/>
From df43551390c0d7e5ab3ed54539e684c1c32d7826 Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Wed, 5 Feb 2025 15:31:23 +0000
Subject: [PATCH 04/36] Finished checks
---
.../Office/ShipmentForm/ShipmentForm.jsx | 39 ++++++++++---------
1 file changed, 21 insertions(+), 18 deletions(-)
diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx
index 08e9e4fdc53..56718759557 100644
--- a/src/components/Office/ShipmentForm/ShipmentForm.jsx
+++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx
@@ -357,11 +357,12 @@ const ShipmentForm = (props) => {
: generatePath(servicesCounselingRoutes.BASE_ORDERS_EDIT_PATH, { moveCode });
const submitMTOShipment = (formValues, actions) => {
- if (formValues.hasTertiaryDestination === 'true' && formValues.secondaryDestination.address.streetAddress1 === '') {
- actions.setFieldError('secondaryDestination.address.streetAddress1', 'destination address required');
+ if (formValues.hasSecondaryDelivery === 'yes' && formValues.delivery.address.streetAddress1 === '') {
+ actions.setFieldError('delivery.address.streetAddress1', 'Delivery address required');
actions.setSubmitting(false);
return;
}
+
if (formValues.hasTertiaryPickup === 'true' && formValues.secondaryPickup.address.streetAddress1 === '') {
actions.setFieldError('secondaryPickup.address.streetAddress1', 'Pickup address required');
actions.setSubmitting(false);
@@ -369,19 +370,22 @@ const ShipmentForm = (props) => {
}
if (formValues.hasTertiaryDelivery === 'yes' && formValues.secondaryDelivery.address.streetAddress1 === '') {
- actions.setFieldError('secondaryDelivery.address.streetAddress1', 'destination address required');
- actions.setSubmitting(false);
- return;
- }
-
- if (formValues.hasTertiaryPickup === 'yes' && formValues.secondaryPickup.address.streetAddress1 === '') {
- actions.setFieldError('secondaryPickup.address.streetAddress1', 'Pickup address required');
+ actions.setFieldError('secondaryDelivery.address.streetAddress1', 'Delivery address required');
actions.setSubmitting(false);
return;
}
//* PPM Shipment *//
if (isPPM) {
+ if (
+ formValues.hasTertiaryDestination === 'true' &&
+ formValues.secondaryDestination.address.streetAddress1 === ''
+ ) {
+ actions.setFieldError('secondaryDestination.address.streetAddress1', 'Destination address required');
+ actions.setSubmitting(false);
+ return;
+ }
+
const ppmShipmentBody = formatPpmShipmentForAPI(formValues);
// Allow blank values to be entered into Pro Gear input fields
@@ -587,8 +591,8 @@ const ShipmentForm = (props) => {
secondaryPickup: hasSecondaryPickup === 'yes' ? secondaryPickup : {},
hasSecondaryDelivery: hasSecondaryDelivery === 'yes',
secondaryDelivery: hasSecondaryDelivery === 'yes' ? secondaryDelivery : {},
- hasTertiaryPickup: hasTertiaryPickup === 'yes',
- tertiaryPickup: hasTertiaryPickup === 'yes' ? tertiaryPickup : {},
+ hasTertiaryPickup: hasTertiaryPickup === 'true',
+ tertiaryPickup: hasTertiaryPickup === 'true' ? tertiaryPickup : {},
hasTertiaryDelivery: hasTertiaryDelivery === 'yes',
tertiaryDelivery: hasTertiaryDelivery === 'yes' ? tertiaryDelivery : {},
});
@@ -680,7 +684,6 @@ const ShipmentForm = (props) => {
hasTertiaryDelivery,
isActualExpenseReimbursement,
} = values;
-
const lengthHasError = !!(
(formikProps.touched.lengthFeet && formikProps.errors.lengthFeet === 'Required') ||
(formikProps.touched.lengthInches && formikProps.errors.lengthFeet === 'Required')
@@ -1020,9 +1023,9 @@ const ShipmentForm = (props) => {
data-testid="has-tertiary-pickup"
label="Yes"
name="hasTertiaryPickup"
- value="yes"
+ value="true"
title="Yes, I have a third pickup address"
- checked={hasTertiaryPickup === 'yes'}
+ checked={hasTertiaryPickup === 'true'}
/>
{
data-testid="no-tertiary-pickup"
label="No"
name="hasTertiaryPickup"
- value="no"
+ value="false"
title="No, I do not have a third pickup address"
- checked={hasTertiaryPickup !== 'yes'}
+ checked={hasTertiaryPickup !== 'true'}
/>
- {hasTertiaryPickup === 'yes' && (
+ {hasTertiaryPickup === 'true' && (
{
name="hasTertiaryPickup"
value="false"
title="No, there is not a third pickup address"
- checked={hasTertiaryPickup !== 'yes'}
+ checked={hasTertiaryPickup !== 'true'}
/>
From a93a18d24541ec49f19dd2887c4fadd2052f1302 Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Wed, 5 Feb 2025 17:02:55 +0000
Subject: [PATCH 05/36] Moved to helper function
---
.../Office/ShipmentForm/ShipmentForm.jsx | 27 +++----------------
src/shared/utils.js | 21 +++++++++++++++
2 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx
index 56718759557..1290a33c810 100644
--- a/src/components/Office/ShipmentForm/ShipmentForm.jsx
+++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx
@@ -70,6 +70,7 @@ import { validateDate } from 'utils/validation';
import { isBooleanFlagEnabled } from 'utils/featureFlags';
import { dateSelectionWeekendHolidayCheck } from 'utils/calendar';
import { datePickerFormat, formatDate } from 'shared/dates';
+import { checkPreceedingAddress } from 'shared/utils';
const ShipmentForm = (props) => {
const {
@@ -357,35 +358,15 @@ const ShipmentForm = (props) => {
: generatePath(servicesCounselingRoutes.BASE_ORDERS_EDIT_PATH, { moveCode });
const submitMTOShipment = (formValues, actions) => {
- if (formValues.hasSecondaryDelivery === 'yes' && formValues.delivery.address.streetAddress1 === '') {
- actions.setFieldError('delivery.address.streetAddress1', 'Delivery address required');
- actions.setSubmitting(false);
- return;
- }
-
- if (formValues.hasTertiaryPickup === 'true' && formValues.secondaryPickup.address.streetAddress1 === '') {
- actions.setFieldError('secondaryPickup.address.streetAddress1', 'Pickup address required');
- actions.setSubmitting(false);
- return;
- }
-
- if (formValues.hasTertiaryDelivery === 'yes' && formValues.secondaryDelivery.address.streetAddress1 === '') {
- actions.setFieldError('secondaryDelivery.address.streetAddress1', 'Delivery address required');
+ const preceedingAddressError = checkPreceedingAddress(formValues);
+ if (preceedingAddressError !== '') {
+ actions.setFieldError(preceedingAddressError, 'Address required');
actions.setSubmitting(false);
return;
}
//* PPM Shipment *//
if (isPPM) {
- if (
- formValues.hasTertiaryDestination === 'true' &&
- formValues.secondaryDestination.address.streetAddress1 === ''
- ) {
- actions.setFieldError('secondaryDestination.address.streetAddress1', 'Destination address required');
- actions.setSubmitting(false);
- return;
- }
-
const ppmShipmentBody = formatPpmShipmentForAPI(formValues);
// Allow blank values to be entered into Pro Gear input fields
diff --git a/src/shared/utils.js b/src/shared/utils.js
index 12ccf91c7a8..cd4c84ed2a9 100644
--- a/src/shared/utils.js
+++ b/src/shared/utils.js
@@ -209,3 +209,24 @@ export function checkAddressTogglesToClearAddresses(body) {
return values;
}
+
+export function checkPreceedingAddress(formValues) {
+ const values = formValues;
+ let formError = '';
+
+ if (values.hasSecondaryDelivery === 'yes' && values.delivery.address.streetAddress1 === '') {
+ formError = 'delivery.address.streetAddress1';
+ }
+
+ if (values.hasTertiaryPickup === 'true' && values.secondaryPickup.address.streetAddress1 === '') {
+ formError = 'secondaryPickup.address.streetAddress1';
+ }
+
+ if (values.hasTertiaryDelivery === 'yes' && values.secondaryDelivery.address.streetAddress1 === '') {
+ formError = 'secondaryDelivery.address.streetAddress1';
+ }
+ if (values.hasTertiaryDestination === 'true' && values.secondaryDestination.address.streetAddress1 === '') {
+ formError = 'secondaryDestination.address.streetAddress1';
+ }
+ return formError;
+}
From 2ca1a1fa5744070de77f3e88665223381c835b3c Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Wed, 5 Feb 2025 17:44:27 +0000
Subject: [PATCH 06/36] changed var
---
.envrc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.envrc b/.envrc
index a33401c69de..c5e72d09ad2 100644
--- a/.envrc
+++ b/.envrc
@@ -137,7 +137,7 @@ export FEATURE_FLAG_SAFETY_MOVE=true
export FEATURE_FLAG_MANAGE_SUPPORTING_DOCS=true
# Feature flags to enable third address
-export FEATURE_FLAG_THIRD_ADDRESS_AVAILABLE=true
+export FEATURE_FLAG_THIRD_ADDRESS_AVAILABLE=false
# Feature flag to disable/enable headquarters role
export FEATURE_FLAG_HEADQUARTERS_ROLE=true
From 3e8d320c843c4fb04fa2d52a963923fcb6cda132 Mon Sep 17 00:00:00 2001
From: Paul Stonebraker
Date: Wed, 5 Feb 2025 18:29:10 +0000
Subject: [PATCH 07/36] update move history to indicate closeout counselors
---
.../MoveHistory/Database/FieldMappings.js | 2 +
.../UpdateAssignedOfficeUser.test.jsx | 65 ++++++++++++-
src/utils/formatters.js | 11 ++-
src/utils/formatters.test.js | 94 ++++++++++++++++++-
4 files changed, 163 insertions(+), 9 deletions(-)
diff --git a/src/constants/MoveHistory/Database/FieldMappings.js b/src/constants/MoveHistory/Database/FieldMappings.js
index fee085a2b95..bdfa842f934 100644
--- a/src/constants/MoveHistory/Database/FieldMappings.js
+++ b/src/constants/MoveHistory/Database/FieldMappings.js
@@ -149,9 +149,11 @@ export default {
approved_at: 'Approved at',
counseling_office_name: 'Counseling office',
assigned_sc: 'Counselor assigned',
+ assigned_sc_ppm: 'Closeout counselor assigned',
assigned_too: 'Task ordering officer assigned',
assigned_tio: 'Task invoicing officer assigned',
re_assigned_sc: 'Counselor reassigned',
+ re_assigned_sc_ppm: 'Closeout counselor reassigned',
re_assigned_too: 'Task ordering officer reassigned',
re_assigned_tio: 'Task invoicing officer reassigned',
available_to_prime_at: 'Available to Prime at',
diff --git a/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/UpdateAssignedOfficeUser.test.jsx b/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/UpdateAssignedOfficeUser.test.jsx
index bc1e6aa2d73..f1223b4b3a5 100644
--- a/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/UpdateAssignedOfficeUser.test.jsx
+++ b/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/UpdateAssignedOfficeUser.test.jsx
@@ -2,6 +2,7 @@ import { screen, render } from '@testing-library/react';
import e from 'constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/UpdateAssignedOfficeUser';
import getTemplate from 'constants/MoveHistory/TemplateManager';
+import { MOVE_STATUSES } from 'shared/constants';
describe('When given a move that has been assigned', () => {
const historyRecord = {
@@ -13,6 +14,7 @@ describe('When given a move that has been assigned', () => {
},
oldValues: {
sc_assigned_id: null,
+ status: MOVE_STATUSES.NEEDS_SERVICE_COUNSELING,
},
context: [{ assigned_office_user_last_name: 'Daniels', assigned_office_user_first_name: 'Jayden' }],
};
@@ -30,14 +32,47 @@ describe('When given a move that has been assigned', () => {
});
describe('displays the proper details for', () => {
- it('services counselor', () => {
+ it('assignment of a services counselor', () => {
const template = getTemplate(historyRecord);
render(template.getDetails(historyRecord));
expect(screen.getByText('Counselor assigned')).toBeInTheDocument();
expect(screen.getByText(': Daniels, Jayden')).toBeInTheDocument();
});
- it('task ordering officer', () => {
+ it('reassignment of a services counselor', () => {
+ const template = getTemplate(historyRecord);
+ historyRecord.oldValues = {
+ sc_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64',
+ status: MOVE_STATUSES.NEEDS_SERVICE_COUNSELING,
+ };
+
+ render(template.getDetails(historyRecord));
+ expect(screen.getByText('Counselor reassigned')).toBeInTheDocument();
+ expect(screen.getByText(': Daniels, Jayden')).toBeInTheDocument();
+ });
+ it('assignment of a closeout counselor', () => {
+ const template = getTemplate(historyRecord);
+ historyRecord.oldValues = {
+ sc_assigned_id: null,
+ status: MOVE_STATUSES.SERVICE_COUNSELING_COMPLETED,
+ };
+
+ render(template.getDetails(historyRecord));
+ expect(screen.getByText('Closeout counselor assigned')).toBeInTheDocument();
+ expect(screen.getByText(': Daniels, Jayden')).toBeInTheDocument();
+ });
+ it('reassignment of a closeout counselor', () => {
+ const template = getTemplate(historyRecord);
+ historyRecord.oldValues = {
+ sc_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64',
+ status: MOVE_STATUSES.SERVICE_COUNSELING_COMPLETED,
+ };
+
+ render(template.getDetails(historyRecord));
+ expect(screen.getByText('Closeout counselor reassigned')).toBeInTheDocument();
+ expect(screen.getByText(': Daniels, Jayden')).toBeInTheDocument();
+ });
+ it('assignment of a task ordering officer', () => {
historyRecord.changedValues = { too_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137' };
historyRecord.oldValues = { too_assigned_id: null };
historyRecord.context = [
@@ -50,7 +85,20 @@ describe('When given a move that has been assigned', () => {
expect(screen.getByText('Task ordering officer assigned')).toBeInTheDocument();
expect(screen.getByText(': Robinson, Brian')).toBeInTheDocument();
});
- it('task invoicing officer', () => {
+ it('reassignment of a task ordering officer', () => {
+ historyRecord.changedValues = { too_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137' };
+ historyRecord.oldValues = { too_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64' };
+ historyRecord.context = [
+ { assigned_office_user_last_name: 'Robinson', assigned_office_user_first_name: 'Brian' },
+ ];
+
+ const template = getTemplate(historyRecord);
+
+ render(template.getDetails(historyRecord));
+ expect(screen.getByText('Task ordering officer reassigned')).toBeInTheDocument();
+ expect(screen.getByText(': Robinson, Brian')).toBeInTheDocument();
+ });
+ it('assignment of a task invoicing officer', () => {
historyRecord.changedValues = { tio_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137' };
historyRecord.oldValues = { tio_assigned_id: null };
historyRecord.context = [{ assigned_office_user_last_name: 'Luvu', assigned_office_user_first_name: 'Frankie' }];
@@ -61,5 +109,16 @@ describe('When given a move that has been assigned', () => {
expect(screen.getByText('Task invoicing officer assigned')).toBeInTheDocument();
expect(screen.getByText(': Luvu, Frankie')).toBeInTheDocument();
});
+ it('reassignment of a task invoicing officer', () => {
+ historyRecord.changedValues = { tio_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137' };
+ historyRecord.oldValues = { tio_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64' };
+ historyRecord.context = [{ assigned_office_user_last_name: 'Luvu', assigned_office_user_first_name: 'Frankie' }];
+
+ const template = getTemplate(historyRecord);
+
+ render(template.getDetails(historyRecord));
+ expect(screen.getByText('Task invoicing officer reassigned')).toBeInTheDocument();
+ expect(screen.getByText(': Luvu, Frankie')).toBeInTheDocument();
+ });
});
});
diff --git a/src/utils/formatters.js b/src/utils/formatters.js
index d979dcdc624..3dff740f21d 100644
--- a/src/utils/formatters.js
+++ b/src/utils/formatters.js
@@ -7,7 +7,7 @@ import { DEPARTMENT_INDICATOR_OPTIONS } from 'constants/departmentIndicators';
import { SERVICE_MEMBER_AGENCY_LABELS } from 'content/serviceMemberAgencies';
import { ORDERS_TYPE_OPTIONS, ORDERS_TYPE_DETAILS_OPTIONS } from 'constants/orders';
import { PAYMENT_REQUEST_STATUS_LABELS } from 'constants/paymentRequestStatus';
-import { DEFAULT_EMPTY_VALUE } from 'shared/constants';
+import { DEFAULT_EMPTY_VALUE, MOVE_STATUSES } from 'shared/constants';
/**
* Formats number into a dollar string. Eg. $1,234.12
@@ -609,8 +609,13 @@ export const formatAssignedOfficeUserFromContext = (historyRecord) => {
const name = `${context[0].assigned_office_user_last_name}, ${context[0].assigned_office_user_first_name}`;
if (changedValues?.sc_assigned_id) {
- if (oldValues.sc_assigned_id === null) newValues.assigned_sc = name;
- if (oldValues.sc_assigned_id !== null) newValues.re_assigned_sc = name;
+ if (oldValues.status === MOVE_STATUSES.NEEDS_SERVICE_COUNSELING) {
+ if (oldValues.sc_assigned_id === null) newValues.assigned_sc = name;
+ if (oldValues.sc_assigned_id !== null) newValues.re_assigned_sc = name;
+ } else {
+ if (oldValues.sc_assigned_id === null) newValues.assigned_sc_ppm = name;
+ if (oldValues.sc_assigned_id !== null) newValues.re_assigned_sc_ppm = name;
+ }
}
if (changedValues?.too_assigned_id) {
if (oldValues.too_assigned_id === null) newValues.assigned_too = name;
diff --git a/src/utils/formatters.test.js b/src/utils/formatters.test.js
index 97b99f470a3..b09ac4b0937 100644
--- a/src/utils/formatters.test.js
+++ b/src/utils/formatters.test.js
@@ -4,6 +4,7 @@ import * as formatters from './formatters';
import { formatQAReportID } from './formatters';
import PAYMENT_REQUEST_STATUS from 'constants/paymentRequestStatus';
+import { MOVE_STATUSES } from 'shared/constants';
describe('formatters', () => {
describe('format date for customer app', () => {
@@ -350,13 +351,14 @@ describe('formatters', () => {
});
describe('formatAssignedOfficeUserFromContext', () => {
- it('properly formats an SCs name', () => {
+ it(`properly formats a Services Counselor's name for assignment`, () => {
const values = {
changedValues: {
sc_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
},
oldValues: {
sc_assigned_id: null,
+ status: MOVE_STATUSES.NEEDS_SERVICE_COUNSELING,
},
context: [{ assigned_office_user_last_name: 'Daniels', assigned_office_user_first_name: 'Jayden' }],
};
@@ -367,8 +369,61 @@ describe('formatAssignedOfficeUserFromContext', () => {
assigned_sc: 'Daniels, Jayden',
});
});
+ it(`properly formats a Services Counselor's name for reassignment`, () => {
+ const values = {
+ changedValues: {
+ sc_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
+ },
+ oldValues: {
+ sc_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64',
+ status: MOVE_STATUSES.NEEDS_SERVICE_COUNSELING,
+ },
+ context: [{ assigned_office_user_last_name: 'Daniels', assigned_office_user_first_name: 'Jayden' }],
+ };
+
+ const result = formatters.formatAssignedOfficeUserFromContext(values);
- it('properly formats a TOOs name', () => {
+ expect(result).toEqual({
+ re_assigned_sc: 'Daniels, Jayden',
+ });
+ });
+ it(`properly formats a Closeout Counselor's name for assignment`, () => {
+ const values = {
+ changedValues: {
+ sc_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
+ },
+ oldValues: {
+ sc_assigned_id: null,
+ status: MOVE_STATUSES.SERVICE_COUNSELING_COMPLETED,
+ },
+ context: [{ assigned_office_user_last_name: 'Daniels', assigned_office_user_first_name: 'Jayden' }],
+ };
+
+ const result = formatters.formatAssignedOfficeUserFromContext(values);
+
+ expect(result).toEqual({
+ assigned_sc_ppm: 'Daniels, Jayden',
+ });
+ });
+ it(`properly formats a Closeout Counselor's name for reassignment`, () => {
+ const values = {
+ changedValues: {
+ sc_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
+ },
+ oldValues: {
+ sc_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64',
+ status: MOVE_STATUSES.SERVICE_COUNSELING_COMPLETED,
+ },
+ context: [{ assigned_office_user_last_name: 'Daniels', assigned_office_user_first_name: 'Jayden' }],
+ };
+
+ const result = formatters.formatAssignedOfficeUserFromContext(values);
+
+ expect(result).toEqual({
+ re_assigned_sc_ppm: 'Daniels, Jayden',
+ });
+ });
+ it('properly formats a TOOs name for assignment', () => {
const values = {
changedValues: {
too_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
@@ -385,8 +440,24 @@ describe('formatAssignedOfficeUserFromContext', () => {
assigned_too: 'McLaurin, Terry',
});
});
+ it('properly formats a TOOs name for reassignment', () => {
+ const values = {
+ changedValues: {
+ too_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
+ },
+ oldValues: {
+ too_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64',
+ },
+ context: [{ assigned_office_user_last_name: 'McLaurin', assigned_office_user_first_name: 'Terry' }],
+ };
+
+ const result = formatters.formatAssignedOfficeUserFromContext(values);
- it('properly formats a TIOs name', () => {
+ expect(result).toEqual({
+ re_assigned_too: 'McLaurin, Terry',
+ });
+ });
+ it('properly formats a TIOs name for assignment', () => {
const values = {
changedValues: {
tio_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
@@ -403,6 +474,23 @@ describe('formatAssignedOfficeUserFromContext', () => {
assigned_tio: 'Robinson, Brian',
});
});
+ it('properly formats a TIOs name for reassignment', () => {
+ const values = {
+ changedValues: {
+ tio_assigned_id: 'fb625e3c-067c-49d7-8fd9-88ef040e6137',
+ },
+ oldValues: {
+ tio_assigned_id: '759a87ad-dc75-4b34-b551-d31309a79f64',
+ },
+ context: [{ assigned_office_user_last_name: 'Robinson', assigned_office_user_first_name: 'Brian' }],
+ };
+
+ const result = formatters.formatAssignedOfficeUserFromContext(values);
+
+ expect(result).toEqual({
+ re_assigned_tio: 'Robinson, Brian',
+ });
+ });
});
describe('constructSCOrderOconusFields', () => {
From 8940a21d85c61de666d9fbe54a9d79d67b11bf73 Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Wed, 5 Feb 2025 18:56:10 +0000
Subject: [PATCH 08/36] Fixed spacing
---
src/shared/utils.js | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/shared/utils.js b/src/shared/utils.js
index cd4c84ed2a9..13720d91ef0 100644
--- a/src/shared/utils.js
+++ b/src/shared/utils.js
@@ -217,11 +217,9 @@ export function checkPreceedingAddress(formValues) {
if (values.hasSecondaryDelivery === 'yes' && values.delivery.address.streetAddress1 === '') {
formError = 'delivery.address.streetAddress1';
}
-
if (values.hasTertiaryPickup === 'true' && values.secondaryPickup.address.streetAddress1 === '') {
formError = 'secondaryPickup.address.streetAddress1';
}
-
if (values.hasTertiaryDelivery === 'yes' && values.secondaryDelivery.address.streetAddress1 === '') {
formError = 'secondaryDelivery.address.streetAddress1';
}
From 4046d860acc0a93e1ec63e23ecb83674a18b4cfb Mon Sep 17 00:00:00 2001
From: Paul Stonebraker
Date: Wed, 5 Feb 2025 20:07:47 +0000
Subject: [PATCH 09/36] update DeleteAssignedOfficeUser.jsx to reflect
counselor vs closeout counselor in move history
---
.../UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.jsx | 8 ++++++--
.../DeleteAssignedOfficeUser.test.jsx | 8 ++++++++
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.jsx b/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.jsx
index e721b67abd0..000e6ec56f7 100644
--- a/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.jsx
+++ b/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.jsx
@@ -3,14 +3,18 @@ import React from 'react';
import o from 'constants/MoveHistory/UIDisplay/Operations';
import a from 'constants/MoveHistory/Database/Actions';
import t from 'constants/MoveHistory/Database/Tables';
+import { MOVE_STATUSES } from 'shared/constants';
export default {
action: a.UPDATE,
eventName: o.deleteAssignedOfficeUser,
tableName: t.moves,
getEventNameDisplay: () => 'Updated move',
- getDetails: ({ changedValues }) => {
- if (changedValues.sc_assigned_id === null) return <>Counselor unassigned>;
+ getDetails: ({ changedValues, oldValues }) => {
+ if (changedValues.sc_assigned_id === null && oldValues?.status === MOVE_STATUSES.NEEDS_SERVICE_COUNSELING)
+ return <>Counselor unassigned>;
+ if (changedValues.sc_assigned_id === null && oldValues?.status !== MOVE_STATUSES.NEEDS_SERVICE_COUNSELING)
+ return <>Closeout counselor unassigned>;
if (changedValues.too_assigned_id === null) return <>Task ordering officer unassigned>;
if (changedValues.tio_assigned_id === null) return <>Task invoicing officer unassigned>;
return <>Unassigned>;
diff --git a/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.test.jsx b/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.test.jsx
index cf02b1f8fb5..5c9a613271b 100644
--- a/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.test.jsx
+++ b/src/constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser.test.jsx
@@ -2,6 +2,7 @@ import { screen, render } from '@testing-library/react';
import e from 'constants/MoveHistory/EventTemplates/UpdateAssignedOfficeUser/DeleteAssignedOfficeUser';
import getTemplate from 'constants/MoveHistory/TemplateManager';
+import { MOVE_STATUSES } from 'shared/constants';
describe('When given a move that has been unassigned', () => {
const historyRecord = {
@@ -26,8 +27,15 @@ describe('When given a move that has been unassigned', () => {
});
describe('displays the proper details for', () => {
+ it('closeout counselor', () => {
+ const template = getTemplate(historyRecord);
+
+ render(template.getDetails(historyRecord));
+ expect(screen.getByText('Closeout counselor unassigned')).toBeInTheDocument();
+ });
it('services counselor', () => {
const template = getTemplate(historyRecord);
+ historyRecord.oldValues = { status: MOVE_STATUSES.NEEDS_SERVICE_COUNSELING };
render(template.getDetails(historyRecord));
expect(screen.getByText('Counselor unassigned')).toBeInTheDocument();
From 87be21382d713769403585c1468660bebf85fa7b Mon Sep 17 00:00:00 2001
From: Brooklyn Welsh
Date: Tue, 28 Jan 2025 12:18:04 -0500
Subject: [PATCH 10/36] Removed unneeded conditional
---
.../ExpandableServiceItemRow/ExpandableServiceItemRow.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx b/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx
index 41e4295c642..e6cbba78392 100644
--- a/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx
+++ b/src/components/Office/ExpandableServiceItemRow/ExpandableServiceItemRow.jsx
@@ -26,7 +26,7 @@ const ExpandableServiceItemRow = ({
};
const canShowExpandableContent =
!disableExpansion &&
- (allowedServiceItemCalculations.includes(serviceItem.mtoServiceItemCode) === true || serviceItem.rejectionReason);
+ (allowedServiceItemCalculations.includes(serviceItem.mtoServiceItemCode) || serviceItem.rejectionReason);
const handleExpandClick = () => {
setIsExpanded((prev) => !prev);
From d0d77164065adf7dd3a52cc02075bf05073326aa Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Thu, 6 Feb 2025 23:03:29 +0000
Subject: [PATCH 11/36] Rework
---
.../Office/ShipmentForm/ShipmentForm.jsx | 82 +++++++++++++++++--
src/shared/utils.js | 39 +++++++++
2 files changed, 112 insertions(+), 9 deletions(-)
diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx
index 1290a33c810..6a627eea98a 100644
--- a/src/components/Office/ShipmentForm/ShipmentForm.jsx
+++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx
@@ -70,7 +70,11 @@ import { validateDate } from 'utils/validation';
import { isBooleanFlagEnabled } from 'utils/featureFlags';
import { dateSelectionWeekendHolidayCheck } from 'utils/calendar';
import { datePickerFormat, formatDate } from 'shared/dates';
-import { checkPreceedingAddress } from 'shared/utils';
+import {
+ isSecondaryPicukupAddressComplete,
+ isSecondaryDeliveryAddressComplete,
+ isDeliveryAddressComplete,
+} from 'shared/utils';
const ShipmentForm = (props) => {
const {
@@ -358,13 +362,6 @@ const ShipmentForm = (props) => {
: generatePath(servicesCounselingRoutes.BASE_ORDERS_EDIT_PATH, { moveCode });
const submitMTOShipment = (formValues, actions) => {
- const preceedingAddressError = checkPreceedingAddress(formValues);
- if (preceedingAddressError !== '') {
- actions.setFieldError(preceedingAddressError, 'Address required');
- actions.setSubmitting(false);
- return;
- }
-
//* PPM Shipment *//
if (isPPM) {
const ppmShipmentBody = formatPpmShipmentForAPI(formValues);
@@ -777,7 +774,6 @@ const ShipmentForm = (props) => {
onErrorHandler,
);
};
-
return (
<>
{
value="true"
title="Yes, I have a third pickup address"
checked={hasTertiaryPickup === 'true'}
+ disabled={
+ !isSecondaryPicukupAddressComplete(
+ hasSecondaryPickup,
+ values.secondaryPickup.address,
+ )
+ }
/>
{
value="false"
title="No, I do not have a third pickup address"
checked={hasTertiaryPickup !== 'true'}
+ disabled={
+ !isSecondaryPicukupAddressComplete(
+ hasSecondaryPickup,
+ values.secondaryPickup.address,
+ )
+ }
/>
@@ -1123,6 +1131,7 @@ const ShipmentForm = (props) => {
value="yes"
title="Yes, I have a second destination location"
checked={hasSecondaryDelivery === 'yes'}
+ disabled={!isDeliveryAddressComplete('yes', values.delivery.address)}
/>
{
value="no"
title="No, I do not have a second destination location"
checked={hasSecondaryDelivery !== 'yes'}
+ disabled={!isDeliveryAddressComplete('yes', values.delivery.address)}
/>
@@ -1158,6 +1168,12 @@ const ShipmentForm = (props) => {
value="yes"
title="Yes, I have a third delivery address"
checked={hasTertiaryDelivery === 'yes'}
+ disabled={
+ !isSecondaryDeliveryAddressComplete(
+ hasSecondaryDelivery,
+ values.secondaryDelivery.address,
+ )
+ }
/>
{
value="no"
title="No, I do not have a third delivery address"
checked={hasTertiaryDelivery !== 'yes'}
+ disabled={
+ !isSecondaryDeliveryAddressComplete(
+ hasSecondaryDelivery,
+ values.secondaryDelivery.address,
+ )
+ }
/>
@@ -1280,6 +1302,9 @@ const ShipmentForm = (props) => {
value="yes"
title="Yes, I have a second destination location"
checked={hasSecondaryDelivery === 'yes'}
+ disabled={
+ !isDeliveryAddressComplete(hasDeliveryAddress, values.delivery.address)
+ }
/>
{
value="no"
title="No, I do not have a second destination location"
checked={hasSecondaryDelivery !== 'yes'}
+ disabled={
+ !isDeliveryAddressComplete(hasDeliveryAddress, values.delivery.address)
+ }
/>
@@ -1317,6 +1345,12 @@ const ShipmentForm = (props) => {
value="yes"
title="Yes, I have a third delivery address"
checked={hasTertiaryDelivery === 'yes'}
+ disabled={
+ !isSecondaryDeliveryAddressComplete(
+ hasSecondaryDelivery,
+ values.secondaryDelivery.address,
+ )
+ }
/>
{
value="no"
title="No, I do not have a third delivery address"
checked={hasTertiaryDelivery !== 'yes'}
+ disabled={
+ !isSecondaryDeliveryAddressComplete(
+ hasSecondaryDelivery,
+ values.secondaryDelivery.address,
+ )
+ }
/>
@@ -1494,6 +1534,12 @@ const ShipmentForm = (props) => {
value="true"
title="Yes, there is a third pickup address"
checked={hasTertiaryPickup === 'true'}
+ disabled={
+ !isSecondaryPicukupAddressComplete(
+ hasSecondaryPickup,
+ values.secondaryPickup.address,
+ )
+ }
/>
{
value="false"
title="No, there is not a third pickup address"
checked={hasTertiaryPickup !== 'true'}
+ disabled={
+ !isSecondaryPicukupAddressComplete(
+ hasSecondaryPickup,
+ values.secondaryPickup.address,
+ )
+ }
/>
@@ -1584,6 +1636,12 @@ const ShipmentForm = (props) => {
value="true"
title="Yes, I have a third delivery address"
checked={hasTertiaryDestination === 'true'}
+ disabled={
+ !isSecondaryDeliveryAddressComplete(
+ hasSecondaryDestination,
+ values.secondaryDestination.address,
+ )
+ }
/>
{
value="false"
title="No, I do not have a third delivery address"
checked={hasTertiaryDestination !== 'true'}
+ disabled={
+ !isSecondaryDeliveryAddressComplete(
+ hasSecondaryDestination,
+ values.secondaryDestination.address,
+ )
+ }
/>
diff --git a/src/shared/utils.js b/src/shared/utils.js
index 13720d91ef0..6d788474779 100644
--- a/src/shared/utils.js
+++ b/src/shared/utils.js
@@ -228,3 +228,42 @@ export function checkPreceedingAddress(formValues) {
}
return formError;
}
+
+export function isSecondaryPicukupAddressComplete(hasSecondaryPickup, addressValues) {
+ if (
+ (hasSecondaryPickup === 'yes' || hasSecondaryPickup === 'true') &&
+ addressValues.streetAddress1 !== '' &&
+ addressValues.state !== '' &&
+ addressValues.city !== '' &&
+ addressValues.postalCode !== ''
+ ) {
+ return true;
+ }
+ return false;
+}
+
+export function isSecondaryDeliveryAddressComplete(hasSecondaryDelivery, addressValues) {
+ if (
+ (hasSecondaryDelivery === 'yes' || hasSecondaryDelivery === 'true') &&
+ addressValues.streetAddress1 !== '' &&
+ addressValues.state !== '' &&
+ addressValues.city !== '' &&
+ addressValues.postalCode !== ''
+ ) {
+ return true;
+ }
+ return false;
+}
+
+export function isDeliveryAddressComplete(hasDeliveryAddress, addressValues) {
+ if (
+ hasDeliveryAddress === 'yes' &&
+ addressValues.streetAddress1 !== '' &&
+ addressValues.state !== '' &&
+ addressValues.city !== '' &&
+ addressValues.postalCode !== ''
+ ) {
+ return true;
+ }
+ return false;
+}
From e19e11c090e40bcb48f2ab856553f7d85636b8a7 Mon Sep 17 00:00:00 2001
From: Tae Jung
Date: Thu, 6 Feb 2025 23:09:22 +0000
Subject: [PATCH 12/36] added frontend work for intl crating and uncrating
payment request
---
pkg/testdatagen/testharness/dispatch.go | 3 +
pkg/testdatagen/testharness/make_move.go | 371 ++++++++++++++++++
.../office/txo/tioFlowsInternational.spec.js | 92 +++++
playwright/tests/utils/testharness.js | 8 +
.../Office/ServiceItemCalculations/helpers.js | 102 ++++-
.../ServiceItemCalculations/helpers.test.js | 28 +-
.../serviceItemTestParams.js | 54 +++
src/constants/serviceItems.js | 13 +-
8 files changed, 663 insertions(+), 8 deletions(-)
diff --git a/pkg/testdatagen/testharness/dispatch.go b/pkg/testdatagen/testharness/dispatch.go
index 0ed11caf74a..f7e39c22f2f 100644
--- a/pkg/testdatagen/testharness/dispatch.go
+++ b/pkg/testdatagen/testharness/dispatch.go
@@ -272,6 +272,9 @@ var actionDispatcher = map[string]actionFunc{
"InternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO": func(appCtx appcontext.AppContext) testHarnessResponse {
return MakeBasicInternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO(appCtx)
},
+ "IntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO": func(appCtx appcontext.AppContext) testHarnessResponse {
+ return MakeIntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO(appCtx)
+ },
}
func Actions() []string {
diff --git a/pkg/testdatagen/testharness/make_move.go b/pkg/testdatagen/testharness/make_move.go
index 3e2f5fed100..16984751b00 100644
--- a/pkg/testdatagen/testharness/make_move.go
+++ b/pkg/testdatagen/testharness/make_move.go
@@ -9380,3 +9380,374 @@ func MakeBasicInternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO(appCt
return *newmove
}
+
+// MakeIntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO creates an iHHG move
+// that has been approved by TOO & prime has requested payment for intl crating and uncrating service items
+func MakeIntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO(appCtx appcontext.AppContext) models.Move {
+ userUploader := newUserUploader(appCtx)
+
+ // Create Customer
+ userInfo := newUserInfo("customer")
+ customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.ServiceMember{
+ PersonalEmail: &userInfo.email,
+ FirstName: &userInfo.firstName,
+ LastName: &userInfo.lastName,
+ CacValidated: true,
+ },
+ },
+ }, nil)
+
+ // address setup
+ addressAK := factory.BuildAddress(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.Address{
+ StreetAddress1: "123 Cold St",
+ City: "Anchorage",
+ State: "AK",
+ PostalCode: "99505",
+ },
+ },
+ }, nil)
+ destDutyLocationAK := factory.BuildDutyLocation(appCtx.DB(), []factory.Customization{
+ {
+ Model: addressAK,
+ LinkOnly: true,
+ },
+ }, nil)
+
+ // orders setup using AK destination duty location
+ orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{
+ {
+ Model: customer,
+ LinkOnly: true,
+ },
+ {
+ Model: models.UserUpload{},
+ ExtendedParams: &factory.UserUploadExtendedParams{
+ UserUploader: userUploader,
+ AppContext: appCtx,
+ },
+ },
+ {
+ Model: models.Order{
+ NewDutyLocationID: destDutyLocationAK.ID,
+ },
+ },
+ }, nil)
+
+ mto := factory.BuildMove(appCtx.DB(), []factory.Customization{
+ {
+ Model: orders,
+ LinkOnly: true,
+ },
+ {
+ Model: models.Move{
+ AvailableToPrimeAt: models.TimePointer(time.Now()),
+ },
+ },
+ }, nil)
+
+ shipmentPickupAddress := factory.BuildAddress(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.Address{
+ // This is a postal code that maps to the default office user gbloc KKFA in the PostalCodeToGBLOC table
+ PostalCode: "85004",
+ },
+ },
+ }, nil)
+ alaskaDestAddress := factory.BuildAddress(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.Address{
+ StreetAddress1: "123 Cold St",
+ City: "Anchorage",
+ State: "AK",
+ PostalCode: "99505",
+ IsOconus: models.BoolPointer(true),
+ },
+ },
+ }, nil)
+
+ estimatedWeight := unit.Pound(2000)
+ actualWeight := unit.Pound(2000)
+ mtoShipmentHHG := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.MTOShipment{
+ PrimeEstimatedWeight: &estimatedWeight,
+ PrimeActualWeight: &actualWeight,
+ ShipmentType: models.MTOShipmentTypeHHG,
+ ApprovedDate: models.TimePointer(time.Now()),
+ MarketCode: models.MarketCodeInternational,
+ },
+ },
+ {
+ Model: shipmentPickupAddress,
+ LinkOnly: true,
+ Type: &factory.Addresses.PickupAddress,
+ },
+ {
+ Model: alaskaDestAddress,
+ LinkOnly: true,
+ Type: &factory.Addresses.DeliveryAddress,
+ },
+ {
+ Model: mto,
+ LinkOnly: true,
+ },
+ }, nil)
+
+ // Create Releasing Agent
+ agentUserInfo := newUserInfo("agent")
+ factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{
+ {
+ Model: mtoShipmentHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: models.MTOAgent{
+ ID: uuid.Must(uuid.NewV4()),
+ FirstName: &agentUserInfo.firstName,
+ LastName: &agentUserInfo.lastName,
+ Email: &agentUserInfo.email,
+ MTOAgentType: models.MTOAgentReleasing,
+ },
+ },
+ }, nil)
+
+ paymentRequestHHG := factory.BuildPaymentRequest(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.PaymentRequest{
+ IsFinal: false,
+ Status: models.PaymentRequestStatusPending,
+ RejectionReason: nil,
+ },
+ },
+ {
+ Model: mto,
+ LinkOnly: true,
+ },
+ }, nil)
+
+ // for soft deleted proof of service docs
+ factory.BuildPrimeUpload(appCtx.DB(), []factory.Customization{
+ {
+ Model: paymentRequestHHG,
+ LinkOnly: true,
+ },
+ }, []factory.Trait{factory.GetTraitPrimeUploadDeleted})
+
+ currentTime := time.Now()
+
+ cratingPaymentServiceItemParams := []factory.CreatePaymentServiceItemParams{
+ {
+ Key: models.ServiceItemParamNameContractCode,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: factory.DefaultContractCode,
+ },
+ {
+ Key: models.ServiceItemParamNameEscalationCompounded,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: strconv.FormatFloat(1.125, 'f', 5, 64),
+ },
+ {
+ Key: models.ServiceItemParamNamePriceRateOrFactor,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "1.71",
+ },
+ {
+ Key: models.ServiceItemParamNameCubicFeetBilled,
+ KeyType: models.ServiceItemParamTypeDecimal,
+ Value: "12",
+ },
+ {
+ Key: models.ServiceItemParamNameReferenceDate,
+ KeyType: models.ServiceItemParamTypeDate,
+ Value: currentTime.Format("2006-01-02"),
+ },
+ {
+ Key: models.ServiceItemParamNameStandaloneCrate,
+ KeyType: models.ServiceItemParamTypeBoolean,
+ Value: strconv.FormatBool(true),
+ },
+ {
+ Key: models.ServiceItemParamNameStandaloneCrateCap,
+ KeyType: models.ServiceItemParamTypeInteger,
+ Value: strconv.FormatInt(100000, 10),
+ },
+ {
+ Key: models.ServiceItemParamNameMarketOrigin,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "O",
+ },
+ {
+ Key: models.ServiceItemParamNameExternalCrate,
+ KeyType: models.ServiceItemParamTypeBoolean,
+ Value: strconv.FormatBool(true),
+ },
+ {
+ Key: models.ServiceItemParamNameDimensionHeight,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "10",
+ },
+ {
+ Key: models.ServiceItemParamNameDimensionLength,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "12",
+ },
+ {
+ Key: models.ServiceItemParamNameDimensionWidth,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "3",
+ },
+ }
+ desc := "description test"
+ icrt := factory.BuildMTOServiceItem(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.MTOServiceItem{
+ Status: models.MTOServiceItemStatusApproved,
+ Description: &desc,
+ StandaloneCrate: models.BoolPointer(true),
+ ExternalCrate: models.BoolPointer(true),
+ },
+ },
+ {
+ Model: mto,
+ LinkOnly: true,
+ },
+ {
+ Model: mtoShipmentHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: models.ReService{
+ Code: models.ReServiceCodeICRT,
+ },
+ },
+ }, nil)
+
+ factory.BuildPaymentServiceItemWithParams(appCtx.DB(), models.ReServiceCodeICRT,
+ cratingPaymentServiceItemParams, []factory.Customization{
+ {
+ Model: mto,
+ LinkOnly: true,
+ },
+ {
+ Model: mtoShipmentHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: paymentRequestHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: icrt,
+ LinkOnly: true,
+ },
+ }, nil)
+
+ iucrt := factory.BuildMTOServiceItem(appCtx.DB(), []factory.Customization{
+ {
+ Model: models.MTOServiceItem{
+ Status: models.MTOServiceItemStatusApproved,
+ Description: &desc,
+ },
+ },
+ {
+ Model: mto,
+ LinkOnly: true,
+ },
+ {
+ Model: mtoShipmentHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: models.ReService{
+ Code: models.ReServiceCodeIUCRT,
+ },
+ },
+ }, nil)
+
+ unCratingPaymentServiceItemParams := []factory.CreatePaymentServiceItemParams{
+ {
+ Key: models.ServiceItemParamNameContractCode,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: factory.DefaultContractCode,
+ },
+ {
+ Key: models.ServiceItemParamNameEscalationCompounded,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: strconv.FormatFloat(1.125, 'f', 5, 64),
+ },
+ {
+ Key: models.ServiceItemParamNamePriceRateOrFactor,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "1.71",
+ },
+ {
+ Key: models.ServiceItemParamNameCubicFeetBilled,
+ KeyType: models.ServiceItemParamTypeDecimal,
+ Value: "12",
+ },
+ {
+ Key: models.ServiceItemParamNameReferenceDate,
+ KeyType: models.ServiceItemParamTypeDate,
+ Value: currentTime.Format("2006-01-02"),
+ },
+ {
+ Key: models.ServiceItemParamNameMarketDest,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "O",
+ },
+ {
+ Key: models.ServiceItemParamNameDimensionHeight,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "10",
+ },
+ {
+ Key: models.ServiceItemParamNameDimensionLength,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "12",
+ },
+ {
+ Key: models.ServiceItemParamNameDimensionWidth,
+ KeyType: models.ServiceItemParamTypeString,
+ Value: "3",
+ },
+ }
+
+ factory.BuildPaymentServiceItemWithParams(appCtx.DB(), models.ReServiceCodeIUCRT,
+ unCratingPaymentServiceItemParams, []factory.Customization{
+ {
+ Model: mto,
+ LinkOnly: true,
+ },
+ {
+ Model: mtoShipmentHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: paymentRequestHHG,
+ LinkOnly: true,
+ },
+ {
+ Model: iucrt,
+ LinkOnly: true,
+ },
+ }, nil)
+
+ // re-fetch the move so that we ensure we have exactly what is in
+ // the db
+ newmove, err := models.FetchMove(appCtx.DB(), &auth.Session{}, mto.ID)
+ if err != nil {
+ log.Panic(fmt.Errorf("failed to fetch move: %w", err))
+ }
+
+ // load payment requests so tests can confirm
+ err = appCtx.DB().Load(newmove, "PaymentRequests")
+ if err != nil {
+ log.Panic(fmt.Errorf("failed to fetch move payment requestse: %w", err))
+ }
+
+ return *newmove
+}
diff --git a/playwright/tests/office/txo/tioFlowsInternational.spec.js b/playwright/tests/office/txo/tioFlowsInternational.spec.js
index 2b97f19078b..bf565aa85c2 100644
--- a/playwright/tests/office/txo/tioFlowsInternational.spec.js
+++ b/playwright/tests/office/txo/tioFlowsInternational.spec.js
@@ -187,4 +187,96 @@ test.describe('TIO user', () => {
// in the TIO queue - only "Payment requested" moves will appear
await expect(paymentSection.locator('td', { hasText: 'Reviewed' })).not.toBeVisible();
});
+
+ test('can review a payment request for international crating/uncrating service items', async ({
+ page,
+ officePage,
+ }) => {
+ test.slow();
+ const move =
+ await officePage.testHarness.buildIntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO();
+ await officePage.signInAsNewTIOUser();
+
+ tioFlowPage = new TioFlowPage(officePage, move, true);
+ await tioFlowPage.waitForLoading();
+ await officePage.tioNavigateToMove(tioFlowPage.moveLocator);
+ await officePage.page.getByRole('heading', { name: 'Payment Requests', exact: true }).waitFor();
+ expect(page.url()).toContain('/payment-requests');
+ await expect(page.getByTestId('MovePaymentRequests')).toBeVisible();
+
+ const prNumber = tioFlowPage.paymentRequest.payment_request_number;
+ const prHeading = page.getByRole('heading', { name: `Payment Request ${prNumber}` });
+ await expect(prHeading).toBeVisible();
+ await tioFlowPage.waitForLoading();
+
+ await page.getByRole('button', { name: 'Review service items' }).click();
+
+ await page.waitForURL(`**/payment-requests/${tioFlowPage.paymentRequest.id}`);
+ await tioFlowPage.waitForLoading();
+
+ // ICRT
+ await expect(page.getByTestId('ReviewServiceItems')).toBeVisible();
+ await expect(page.getByText('International crating')).toBeVisible();
+ await page.getByText('Show calculations').click();
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Calculations');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Crating size (cu ft)');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Description');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Dimensions');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('External crate');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Crating price (per cu ft)');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Market');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Crating date');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('International');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Price escalation factor');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Uncapped request total');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Standalone crate cap');
+ // approve
+ await tioFlowPage.approveServiceItem();
+ await page.getByTestId('nextServiceItem').click();
+ await tioFlowPage.slowDown();
+
+ // IUCRT
+ await expect(page.getByText('International uncrating')).toBeVisible();
+ await page.getByText('Show calculations').click();
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Calculations');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Crating size (cu ft)');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Description');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Dimensions');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Uncrating price (per cu ft)');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Market');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Uncrating date');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('International');
+ await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Price escalation factor');
+ // approve
+ await tioFlowPage.approveServiceItem();
+ await page.getByTestId('nextServiceItem').click();
+ await tioFlowPage.slowDown();
+
+ await expect(page.getByText('needs your review')).toHaveCount(0, { timeout: 10000 });
+ await page.getByText('Complete request').click();
+
+ await page.getByText('Authorize payment').click();
+ await tioFlowPage.waitForLoading();
+
+ await tioFlowPage.slowDown();
+ expect(page.url()).toContain('/payment-requests');
+
+ await expect(page.getByTestId('tag')).toBeVisible();
+ await expect(page.getByTestId('tag').getByText('Reviewed')).toHaveCount(1);
+
+ // ensure the payment request we approved no longer has the "Review Service Items" button
+ await expect(page.getByText('Review Service Items')).toHaveCount(0);
+
+ // Go back to queue
+ await page.locator('a[title="Home"]').click();
+ await tioFlowPage.waitForLoading();
+
+ // search for the moveLocator in case this move doesn't show up on the first page
+ await page.locator('#locator').fill(tioFlowPage.moveLocator);
+ await page.locator('#locator').blur();
+ const paymentSection = page.locator(`[data-uuid="${tioFlowPage.paymentRequest.id}"]`);
+ // the payment request that is now in the "Reviewed" status will no longer appear
+ // in the TIO queue - only "Payment requested" moves will appear
+ await expect(paymentSection.locator('td', { hasText: 'Reviewed' })).not.toBeVisible();
+ });
});
diff --git a/playwright/tests/utils/testharness.js b/playwright/tests/utils/testharness.js
index cc84f4c61f9..9a9e6ebb124 100644
--- a/playwright/tests/utils/testharness.js
+++ b/playwright/tests/utils/testharness.js
@@ -387,6 +387,14 @@ export class TestHarness {
return this.buildDefault('InternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO');
}
+ /**
+ * Use testharness to build ihhg move for TIO
+ * @returns {Promise}
+ */
+ async buildIntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO() {
+ return this.buildDefault('IntlHHGMoveWithCratingUncratingServiceItemsAndPaymentRequestsForTIO');
+ }
+
/**
* Use testharness to build hhg move for QAE
* @returns {Promise}
diff --git a/src/components/Office/ServiceItemCalculations/helpers.js b/src/components/Office/ServiceItemCalculations/helpers.js
index c5d26d73e75..6621896a7ff 100644
--- a/src/components/Office/ServiceItemCalculations/helpers.js
+++ b/src/components/Office/ServiceItemCalculations/helpers.js
@@ -28,6 +28,22 @@ const peak = (params) => {
}`;
};
+const market = (params) => {
+ let marketText = `${SERVICE_ITEM_CALCULATION_LABELS.Market}: `;
+
+ if (getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params)) {
+ marketText += ` ${
+ getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params)?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'
+ }`;
+ } else {
+ marketText += ` ${
+ getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketDest, params)?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'
+ }`;
+ }
+
+ return marketText;
+};
+
const serviceAreaOrigin = (params) => {
return `${SERVICE_ITEM_CALCULATION_LABELS[SERVICE_ITEM_PARAM_KEYS.ServiceAreaOrigin]}: ${getParamValue(
SERVICE_ITEM_PARAM_KEYS.ServiceAreaOrigin,
@@ -647,18 +663,71 @@ const unCratingPrice = (params) => {
);
};
+const cratingPriceIntl = (params) => {
+ const value = getParamValue(SERVICE_ITEM_PARAM_KEYS.PriceRateOrFactor, params);
+ const label = SERVICE_ITEM_CALCULATION_LABELS.CratingPrice;
+
+ return calculation(
+ value,
+ label,
+ formatDetail(market(params)),
+ formatDetail(cratingDate(params)),
+ formatDetail(SERVICE_ITEM_CALCULATION_LABELS.International),
+ );
+};
+
+const unCratingPriceIntl = (params) => {
+ const value = getParamValue(SERVICE_ITEM_PARAM_KEYS.PriceRateOrFactor, params);
+ const label = SERVICE_ITEM_CALCULATION_LABELS.UncratingPrice;
+
+ return calculation(
+ value,
+ label,
+ formatDetail(market(params)),
+ formatDetail(unCratingDate(params)),
+ formatDetail(SERVICE_ITEM_CALCULATION_LABELS.International),
+ );
+};
+
const cratingSize = (params, mtoParams) => {
- const value = getParamValue(SERVICE_ITEM_PARAM_KEYS.CubicFeetBilled, params);
+ const cubicFeetBilled = getParamValue(SERVICE_ITEM_PARAM_KEYS.CubicFeetBilled, params);
const length = getParamValue(SERVICE_ITEM_PARAM_KEYS.DimensionLength, params);
const height = getParamValue(SERVICE_ITEM_PARAM_KEYS.DimensionHeight, params);
const width = getParamValue(SERVICE_ITEM_PARAM_KEYS.DimensionWidth, params);
- const label = SERVICE_ITEM_CALCULATION_LABELS.CubicFeetBilled;
+ let label = SERVICE_ITEM_CALCULATION_LABELS.CubicFeetBilled;
const description = `${SERVICE_ITEM_CALCULATION_LABELS.Description}: ${mtoParams.description}`;
const formattedDimensions = `${SERVICE_ITEM_CALCULATION_LABELS.Dimensions}: ${length}x${width}x${height} in`;
- return calculation(value, label, formatDetail(description), formatDetail(formattedDimensions));
+ const externalCrate =
+ getParamValue(SERVICE_ITEM_PARAM_KEYS.ExternalCrate, params)?.toLowerCase() === 'true'
+ ? SERVICE_ITEM_CALCULATION_LABELS.ExternalCrate
+ : '';
+
+ // currently external intl crate gets 4 cu ft min applied to pricing
+ const minimumSizeApplied = externalCrate && cubicFeetBilled.toString() === '4.00';
+
+ if (minimumSizeApplied) {
+ label += ' - Minimum';
+ }
+
+ // show actual size if minimum was applied
+ const cubicFeetCrating = minimumSizeApplied
+ ? `${SERVICE_ITEM_CALCULATION_LABELS.CubicFeetCrating}: ${getParamValue(
+ SERVICE_ITEM_PARAM_KEYS.CubicFeetCrating,
+ params,
+ )} cu ft`
+ : '';
+
+ return calculation(
+ cubicFeetBilled,
+ label,
+ formatDetail(description),
+ formatDetail(formattedDimensions),
+ formatDetail(cubicFeetCrating),
+ formatDetail(externalCrate),
+ );
};
const standaloneCrate = (params) => {
@@ -680,7 +749,7 @@ const standaloneCrate = (params) => {
const uncappedRequestTotal = (params) => {
const uncappedTotal = getParamValue(SERVICE_ITEM_PARAM_KEYS.UncappedRequestTotal, params);
const value = toDollarString(uncappedTotal);
- const label = `${SERVICE_ITEM_CALCULATION_LABELS.UncappedRequestTotal}:`;
+ const label = `${SERVICE_ITEM_CALCULATION_LABELS.UncappedRequestTotal}`;
return calculation(value, label);
};
@@ -950,6 +1019,31 @@ export default function makeCalculations(itemCode, totalAmount, params, mtoParam
totalAmountRequested(totalAmount),
];
break;
+ // International crating
+ case SERVICE_ITEM_CODES.ICRT:
+ result = [
+ cratingSize(params, mtoParams),
+ cratingPriceIntl(params),
+ priceEscalationFactorWithoutContractYear(params),
+ totalAmountRequested(totalAmount),
+ ];
+ if (
+ SERVICE_ITEM_PARAM_KEYS.StandaloneCrate !== null &&
+ getParamValue(SERVICE_ITEM_PARAM_KEYS.StandaloneCrate, params) === 'true'
+ ) {
+ result.splice(result.length - 1, 0, uncappedRequestTotal(params));
+ result.splice(result.length - 1, 0, standaloneCrate(params));
+ }
+ break;
+ // International uncrating
+ case SERVICE_ITEM_CODES.IUCRT:
+ result = [
+ cratingSize(params, mtoParams),
+ unCratingPriceIntl(params),
+ priceEscalationFactorWithoutContractYear(params),
+ totalAmountRequested(totalAmount),
+ ];
+ break;
default:
break;
}
diff --git a/src/components/Office/ServiceItemCalculations/helpers.test.js b/src/components/Office/ServiceItemCalculations/helpers.test.js
index 8ca38112f65..4ff4fb3e02b 100644
--- a/src/components/Office/ServiceItemCalculations/helpers.test.js
+++ b/src/components/Office/ServiceItemCalculations/helpers.test.js
@@ -11,12 +11,12 @@ function testData(code) {
'Crating size (cu ft)': '4.00',
};
}
- if (code === 'DCRT') {
+ if (code === 'DCRT' || code === 'ICRT') {
result = {
...result,
'Crating price (per cu ft)': '1.71',
};
- } else if (code === 'DUCRT') {
+ } else if (code === 'DUCRT' || code === 'IUCRT') {
result = {
...result,
'Uncrating price (per cu ft)': '1.71',
@@ -363,4 +363,28 @@ describe('DomesticDestinationSITDelivery', () => {
const expected = testData('PODFSC');
testAB(result, expected);
});
+
+ it('returns correct data for ICRT', () => {
+ const result = makeCalculations(
+ 'ICRT',
+ 99999,
+ testParams.InternationalCrating,
+ testParams.additionalCratingDataDCRT,
+ );
+ const expected = testData('ICRT');
+
+ testAB(result, expected);
+ });
+
+ it('returns correct data for IUCRT', () => {
+ const result = makeCalculations(
+ 'IUCRT',
+ 99999,
+ testParams.InternationalUncrating,
+ testParams.additionalCratingDataDCRT,
+ );
+ const expected = testData('IUCRT');
+
+ testAB(result, expected);
+ });
});
diff --git a/src/components/Office/ServiceItemCalculations/serviceItemTestParams.js b/src/components/Office/ServiceItemCalculations/serviceItemTestParams.js
index e234dc167c9..bf29cdd1807 100644
--- a/src/components/Office/ServiceItemCalculations/serviceItemTestParams.js
+++ b/src/components/Office/ServiceItemCalculations/serviceItemTestParams.js
@@ -493,6 +493,33 @@ const PortZip = {
type: 'STRING',
value: '99505',
};
+const ExternalCrate = {
+ eTag: 'MjAyMS0wNy0yOVQyMDoxNTowMS4xNDA1MjZa',
+ id: 'f5bb063e-38da-4c86-88ce-a6a328e70b92',
+ key: 'ExternalCrate',
+ origin: 'PRIME',
+ paymentServiceItemID: '28039a62-387d-479f-b50f-e0041b7e6e22',
+ type: 'BOOLEAN',
+ value: 'FALSE',
+};
+const MarketOrigin = {
+ eTag: 'MjAyMS0wNy0yOVQyMDoxNTowMS4xNDA1MjZa',
+ id: 'f5bb063e-38da-4c86-88ce-a6a328e70b92',
+ key: 'MarketOrigin',
+ origin: 'PRIME',
+ paymentServiceItemID: '28039a62-387d-479f-b50f-e0041b7e6e22',
+ type: 'STRING',
+ value: 'O',
+};
+const MarketDest = {
+ eTag: 'MjAyMS0wNy0yOVQyMDoxNTowMS4xNDA1MjZa',
+ id: 'f5bb063e-38da-4c86-88ce-a6a328e70b92',
+ key: 'MarketDest',
+ origin: 'PRIME',
+ paymentServiceItemID: '28039a62-387d-479f-b50f-e0041b7e6e22',
+ type: 'STRING',
+ value: 'C',
+};
const testParams = {
DomesticLongHaul: [
ContractCode,
@@ -916,6 +943,33 @@ const testParams = {
ZipPickupAddress,
PortZip,
],
+ InternationalCrating: [
+ ContractYearName,
+ EscalationCompounded,
+ PriceRateOrFactor,
+ ReferenceDate,
+ CubicFeetBilled,
+ MarketOrigin,
+ ServiceAreaOrigin,
+ ZipPickupAddress,
+ DimensionWidth,
+ DimensionHeight,
+ DimensionLength,
+ StandaloneCrate,
+ ExternalCrate,
+ ],
+ InternationalUncrating: [
+ ReferenceDate,
+ EscalationCompounded,
+ CubicFeetBilled,
+ PriceRateOrFactor,
+ MarketDest,
+ ServiceAreaDest,
+ ZipDestAddress,
+ DimensionWidth,
+ DimensionHeight,
+ DimensionLength,
+ ],
additionalCratingDataDCRT: {
reServiceCode: 'DCRT',
description: 'Grand piano',
diff --git a/src/constants/serviceItems.js b/src/constants/serviceItems.js
index 213afb45f38..9c3f3d1db23 100644
--- a/src/constants/serviceItems.js
+++ b/src/constants/serviceItems.js
@@ -17,10 +17,13 @@ const SERVICE_ITEM_PARAM_KEYS = {
DistanceZipSITDest: 'DistanceZipSITDest',
DistanceZipSITOrigin: 'DistanceZipSITOrigin',
EIAFuelPrice: 'EIAFuelPrice',
+ ExternalCrate: 'ExternalCrate',
FSCPriceDifferenceInCents: 'FSCPriceDifferenceInCents',
EscalationCompounded: 'EscalationCompounded',
FSCWeightBasedDistanceMultiplier: 'FSCWeightBasedDistanceMultiplier',
IsPeak: 'IsPeak',
+ MarketDest: 'MarketDest',
+ MarketOrigin: 'MarketOrigin',
NTSPackingFactor: 'NTSPackingFactor',
NumberDaysSIT: 'NumberDaysSIT',
OriginPrice: 'OriginPrice',
@@ -59,8 +62,10 @@ const SERVICE_ITEM_PARAM_KEYS = {
const SERVICE_ITEM_CALCULATION_LABELS = {
[SERVICE_ITEM_PARAM_KEYS.ActualPickupDate]: 'Pickup date',
[SERVICE_ITEM_PARAM_KEYS.ContractYearName]: 'Base year',
+ [SERVICE_ITEM_PARAM_KEYS.CubicFeetCrating]: 'Actual size',
[SERVICE_ITEM_PARAM_KEYS.DestinationPrice]: 'Destination price',
[SERVICE_ITEM_PARAM_KEYS.EIAFuelPrice]: 'EIA diesel',
+ [SERVICE_ITEM_PARAM_KEYS.ExternalCrate]: 'External crate',
[SERVICE_ITEM_PARAM_KEYS.FSCPriceDifferenceInCents]: 'Baseline rate difference',
[SERVICE_ITEM_PARAM_KEYS.FSCWeightBasedDistanceMultiplier]: 'Weight-based distance multiplier',
// Domestic non-peak or Domestic peak
@@ -101,7 +106,9 @@ const SERVICE_ITEM_CALCULATION_LABELS = {
Dimensions: 'Dimensions',
Domestic: 'Domestic',
FuelSurchargePrice: 'Mileage factor',
+ International: 'International',
InternationalShippingAndLinehaul: 'ISLH price',
+ Market: 'Market',
Mileage: 'Mileage',
MileageIntoSIT: 'Mileage into SIT',
MileageOutOfSIT: 'Mileage out of SIT',
@@ -121,8 +128,8 @@ const SERVICE_ITEM_CALCULATION_LABELS = {
UncratingDate: 'Uncrating date',
UncratingPrice: 'Uncrating price (per cu ft)',
SITFuelSurchargePrice: 'SIT mileage factor',
- StandaloneCrate: 'Standalone Crate Cap',
- UncappedRequestTotal: 'Uncapped Request Total',
+ StandaloneCrate: 'Standalone crate cap',
+ UncappedRequestTotal: 'Uncapped request total',
Total: 'Total',
};
@@ -234,6 +241,8 @@ const allowedServiceItemCalculations = [
SERVICE_ITEM_CODES.ISLH,
SERVICE_ITEM_CODES.POEFSC,
SERVICE_ITEM_CODES.PODFSC,
+ SERVICE_ITEM_CODES.ICRT,
+ SERVICE_ITEM_CODES.IUCRT,
];
export default SERVICE_ITEM_STATUSES;
From 72dd20bd21f855ee896cf1e895beca184feb5c00 Mon Sep 17 00:00:00 2001
From: joeydoyecaci
Date: Fri, 7 Feb 2025 20:30:47 +0000
Subject: [PATCH 13/36] Fixed 'mailto:' email link
---
src/shared/ErrorModal/ErrorModal.jsx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/shared/ErrorModal/ErrorModal.jsx b/src/shared/ErrorModal/ErrorModal.jsx
index b5533a20c58..2706dce1c8c 100644
--- a/src/shared/ErrorModal/ErrorModal.jsx
+++ b/src/shared/ErrorModal/ErrorModal.jsx
@@ -11,9 +11,7 @@ export const ErrorModal = ({ closeModal, errorMessage, displayHelpDeskLink = tru
{errorMessage}
- {displayHelpDeskLink && (
- Technical Help Desk
- )}
+ {displayHelpDeskLink && Technical Help Desk}
+ Be advised, if you are moving to an administratively restricted HHG weight location this amount could be less.
+
If you move more than 7,999 pounds or ship to/from an other than authorized location, you may owe the
From 1f242fe72c85448aa19d2db472c1def79f0da58e Mon Sep 17 00:00:00 2001
From: Tae Jung
Date: Mon, 10 Feb 2025 21:46:46 +0000
Subject: [PATCH 28/36] int merge changes
---
pkg/services/mocks/IntlCratingPricer.go | 109 ++++++++++++++++++
pkg/services/mocks/IntlUncratingPricer.go | 109 ++++++++++++++++++
.../office/txo/tioFlowsInternational.spec.js | 4 -
.../Office/ServiceItemCalculations/helpers.js | 24 +---
4 files changed, 224 insertions(+), 22 deletions(-)
create mode 100644 pkg/services/mocks/IntlCratingPricer.go
create mode 100644 pkg/services/mocks/IntlUncratingPricer.go
diff --git a/pkg/services/mocks/IntlCratingPricer.go b/pkg/services/mocks/IntlCratingPricer.go
new file mode 100644
index 00000000000..0ada84deb77
--- /dev/null
+++ b/pkg/services/mocks/IntlCratingPricer.go
@@ -0,0 +1,109 @@
+// Code generated by mockery. DO NOT EDIT.
+
+package mocks
+
+import (
+ mock "github.com/stretchr/testify/mock"
+ appcontext "github.com/transcom/mymove/pkg/appcontext"
+
+ models "github.com/transcom/mymove/pkg/models"
+
+ services "github.com/transcom/mymove/pkg/services"
+
+ time "time"
+
+ unit "github.com/transcom/mymove/pkg/unit"
+)
+
+// IntlCratingPricer is an autogenerated mock type for the IntlCratingPricer type
+type IntlCratingPricer struct {
+ mock.Mock
+}
+
+// Price provides a mock function with given fields: appCtx, contractCode, requestedPickupDate, billedCubicFeet, standaloneCrate, standaloneCrateCap, externalCrate, market
+func (_m *IntlCratingPricer) Price(appCtx appcontext.AppContext, contractCode string, requestedPickupDate time.Time, billedCubicFeet unit.CubicFeet, standaloneCrate bool, standaloneCrateCap unit.Cents, externalCrate bool, market models.Market) (unit.Cents, services.PricingDisplayParams, error) {
+ ret := _m.Called(appCtx, contractCode, requestedPickupDate, billedCubicFeet, standaloneCrate, standaloneCrateCap, externalCrate, market)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Price")
+ }
+
+ var r0 unit.Cents
+ var r1 services.PricingDisplayParams
+ var r2 error
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, bool, unit.Cents, bool, models.Market) (unit.Cents, services.PricingDisplayParams, error)); ok {
+ return rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, standaloneCrate, standaloneCrateCap, externalCrate, market)
+ }
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, bool, unit.Cents, bool, models.Market) unit.Cents); ok {
+ r0 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, standaloneCrate, standaloneCrateCap, externalCrate, market)
+ } else {
+ r0 = ret.Get(0).(unit.Cents)
+ }
+
+ if rf, ok := ret.Get(1).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, bool, unit.Cents, bool, models.Market) services.PricingDisplayParams); ok {
+ r1 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, standaloneCrate, standaloneCrateCap, externalCrate, market)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(services.PricingDisplayParams)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, bool, unit.Cents, bool, models.Market) error); ok {
+ r2 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, standaloneCrate, standaloneCrateCap, externalCrate, market)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// PriceUsingParams provides a mock function with given fields: appCtx, params
+func (_m *IntlCratingPricer) PriceUsingParams(appCtx appcontext.AppContext, params models.PaymentServiceItemParams) (unit.Cents, services.PricingDisplayParams, error) {
+ ret := _m.Called(appCtx, params)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PriceUsingParams")
+ }
+
+ var r0 unit.Cents
+ var r1 services.PricingDisplayParams
+ var r2 error
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.PaymentServiceItemParams) (unit.Cents, services.PricingDisplayParams, error)); ok {
+ return rf(appCtx, params)
+ }
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.PaymentServiceItemParams) unit.Cents); ok {
+ r0 = rf(appCtx, params)
+ } else {
+ r0 = ret.Get(0).(unit.Cents)
+ }
+
+ if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.PaymentServiceItemParams) services.PricingDisplayParams); ok {
+ r1 = rf(appCtx, params)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(services.PricingDisplayParams)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(appcontext.AppContext, models.PaymentServiceItemParams) error); ok {
+ r2 = rf(appCtx, params)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// NewIntlCratingPricer creates a new instance of IntlCratingPricer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewIntlCratingPricer(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *IntlCratingPricer {
+ mock := &IntlCratingPricer{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/pkg/services/mocks/IntlUncratingPricer.go b/pkg/services/mocks/IntlUncratingPricer.go
new file mode 100644
index 00000000000..c54879fbce8
--- /dev/null
+++ b/pkg/services/mocks/IntlUncratingPricer.go
@@ -0,0 +1,109 @@
+// Code generated by mockery. DO NOT EDIT.
+
+package mocks
+
+import (
+ mock "github.com/stretchr/testify/mock"
+ appcontext "github.com/transcom/mymove/pkg/appcontext"
+
+ models "github.com/transcom/mymove/pkg/models"
+
+ services "github.com/transcom/mymove/pkg/services"
+
+ time "time"
+
+ unit "github.com/transcom/mymove/pkg/unit"
+)
+
+// IntlUncratingPricer is an autogenerated mock type for the IntlUncratingPricer type
+type IntlUncratingPricer struct {
+ mock.Mock
+}
+
+// Price provides a mock function with given fields: appCtx, contractCode, requestedPickupDate, billedCubicFeet, market
+func (_m *IntlUncratingPricer) Price(appCtx appcontext.AppContext, contractCode string, requestedPickupDate time.Time, billedCubicFeet unit.CubicFeet, market models.Market) (unit.Cents, services.PricingDisplayParams, error) {
+ ret := _m.Called(appCtx, contractCode, requestedPickupDate, billedCubicFeet, market)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Price")
+ }
+
+ var r0 unit.Cents
+ var r1 services.PricingDisplayParams
+ var r2 error
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, models.Market) (unit.Cents, services.PricingDisplayParams, error)); ok {
+ return rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, market)
+ }
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, models.Market) unit.Cents); ok {
+ r0 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, market)
+ } else {
+ r0 = ret.Get(0).(unit.Cents)
+ }
+
+ if rf, ok := ret.Get(1).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, models.Market) services.PricingDisplayParams); ok {
+ r1 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, market)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(services.PricingDisplayParams)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(appcontext.AppContext, string, time.Time, unit.CubicFeet, models.Market) error); ok {
+ r2 = rf(appCtx, contractCode, requestedPickupDate, billedCubicFeet, market)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// PriceUsingParams provides a mock function with given fields: appCtx, params
+func (_m *IntlUncratingPricer) PriceUsingParams(appCtx appcontext.AppContext, params models.PaymentServiceItemParams) (unit.Cents, services.PricingDisplayParams, error) {
+ ret := _m.Called(appCtx, params)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PriceUsingParams")
+ }
+
+ var r0 unit.Cents
+ var r1 services.PricingDisplayParams
+ var r2 error
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.PaymentServiceItemParams) (unit.Cents, services.PricingDisplayParams, error)); ok {
+ return rf(appCtx, params)
+ }
+ if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.PaymentServiceItemParams) unit.Cents); ok {
+ r0 = rf(appCtx, params)
+ } else {
+ r0 = ret.Get(0).(unit.Cents)
+ }
+
+ if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.PaymentServiceItemParams) services.PricingDisplayParams); ok {
+ r1 = rf(appCtx, params)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(services.PricingDisplayParams)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(appcontext.AppContext, models.PaymentServiceItemParams) error); ok {
+ r2 = rf(appCtx, params)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// NewIntlUncratingPricer creates a new instance of IntlUncratingPricer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewIntlUncratingPricer(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *IntlUncratingPricer {
+ mock := &IntlUncratingPricer{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/playwright/tests/office/txo/tioFlowsInternational.spec.js b/playwright/tests/office/txo/tioFlowsInternational.spec.js
index a002dc505ee..30f4c0b0dac 100644
--- a/playwright/tests/office/txo/tioFlowsInternational.spec.js
+++ b/playwright/tests/office/txo/tioFlowsInternational.spec.js
@@ -225,9 +225,7 @@ test.describe('TIO user', () => {
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Actual size');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('External crate');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Crating price (per cu ft)');
- await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Market');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Crating date');
- await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('International');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Price escalation factor');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Uncapped request total');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Standalone crate cap');
@@ -245,9 +243,7 @@ test.describe('TIO user', () => {
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Description');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Dimensions');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Uncrating price (per cu ft)');
- await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Market');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Uncrating date');
- await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('International');
await expect(page.locator('[data-testid="ServiceItemCalculations"]')).toContainText('Price escalation factor');
// approve
await tioFlowPage.approveServiceItem();
diff --git a/src/components/Office/ServiceItemCalculations/helpers.js b/src/components/Office/ServiceItemCalculations/helpers.js
index 4161c256d12..ded0b5f0d5f 100644
--- a/src/components/Office/ServiceItemCalculations/helpers.js
+++ b/src/components/Office/ServiceItemCalculations/helpers.js
@@ -33,15 +33,15 @@ const peak = (params) => {
}`;
};
-const market = (params) => {
- let marketText = `${SERVICE_ITEM_CALCULATION_LABELS.Market}: `;
+const getMarket = (params) => {
+ let marketText = '';
if (getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params)) {
- marketText += ` ${
+ marketText = ` ${
getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params)?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'
}`;
} else {
- marketText += ` ${
+ marketText = ` ${
getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketDest, params)?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'
}`;
}
@@ -672,26 +672,14 @@ const cratingPriceIntl = (params) => {
const value = getParamValue(SERVICE_ITEM_PARAM_KEYS.PriceRateOrFactor, params);
const label = SERVICE_ITEM_CALCULATION_LABELS.CratingPrice;
- return calculation(
- value,
- label,
- formatDetail(market(params)),
- formatDetail(cratingDate(params)),
- formatDetail(SERVICE_ITEM_CALCULATION_LABELS.International),
- );
+ return calculation(value, label, formatDetail(cratingDate(params)), formatDetail(getMarket(params)));
};
const unCratingPriceIntl = (params) => {
const value = getParamValue(SERVICE_ITEM_PARAM_KEYS.PriceRateOrFactor, params);
const label = SERVICE_ITEM_CALCULATION_LABELS.UncratingPrice;
- return calculation(
- value,
- label,
- formatDetail(market(params)),
- formatDetail(unCratingDate(params)),
- formatDetail(SERVICE_ITEM_CALCULATION_LABELS.International),
- );
+ return calculation(value, label, formatDetail(unCratingDate(params)), formatDetail(getMarket(params)));
};
const isExternalCrateMinSizeApplied = (params) => {
From fe3eb02898d81f8d26654fedf3edf43848924aa5 Mon Sep 17 00:00:00 2001
From: Tae Jung
Date: Mon, 10 Feb 2025 21:48:49 +0000
Subject: [PATCH 29/36] int merge changes
---
src/constants/serviceItems.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/constants/serviceItems.js b/src/constants/serviceItems.js
index cc73b0bd0b3..9e16a05ff17 100644
--- a/src/constants/serviceItems.js
+++ b/src/constants/serviceItems.js
@@ -22,8 +22,6 @@ const SERVICE_ITEM_PARAM_KEYS = {
EscalationCompounded: 'EscalationCompounded',
FSCWeightBasedDistanceMultiplier: 'FSCWeightBasedDistanceMultiplier',
IsPeak: 'IsPeak',
- MarketDest: 'MarketDest',
- MarketOrigin: 'MarketOrigin',
NTSPackingFactor: 'NTSPackingFactor',
NumberDaysSIT: 'NumberDaysSIT',
OriginPrice: 'OriginPrice',
@@ -57,6 +55,8 @@ const SERVICE_ITEM_PARAM_KEYS = {
StandaloneCrate: 'StandaloneCrate',
StandaloneCrateCap: 'StandaloneCrateCap',
UncappedRequestTotal: 'UncappedRequestTotal',
+ MarketOrigin: 'MarketOrigin',
+ MarketDest: 'MarketDest',
};
const SERVICE_ITEM_CALCULATION_LABELS = {
@@ -106,7 +106,6 @@ const SERVICE_ITEM_CALCULATION_LABELS = {
Dimensions: 'Dimensions',
Domestic: 'Domestic',
FuelSurchargePrice: 'Mileage factor',
- International: 'International',
InternationalShippingAndLinehaul: 'ISLH price',
Market: 'Market',
Mileage: 'Mileage',
From 17cb40896317dc4be9b8cfe76eda30ada0956618 Mon Sep 17 00:00:00 2001
From: pambecker
Date: Mon, 10 Feb 2025 16:03:40 -0600
Subject: [PATCH 30/36] fix issue with servicemember coming back null when
getting orders for oconus destinations
---
pkg/models/move.go | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/pkg/models/move.go b/pkg/models/move.go
index e3b1b889bf8..b66ebd3ecc3 100644
--- a/pkg/models/move.go
+++ b/pkg/models/move.go
@@ -217,13 +217,19 @@ func (m Move) GetDestinationGBLOC(db *pop.Connection) (string, error) {
var newGBLOC string
if *destinationAddress.IsOconus {
- err := db.Load(&m.Orders, "ServiceMember")
- if err != nil {
- if err.Error() == RecordNotFoundErrorString {
- return "", errors.WithMessage(err, "No Service Member found in the DB associated with moveID "+m.ID.String())
+ if m.OrdersID != uuid.Nil {
+ err := db.Q().EagerPreload("ServiceMember").
+ Find(&m.Orders, m.OrdersID)
+ if err != nil {
+ if errors.Cause(err).Error() == RecordNotFoundErrorString {
+ return "", ErrFetchNotFound
+ }
+ return "", err
}
- return "", err
+ } else {
+ return "", errors.WithMessage(ErrInvalidOrderID, "Orders ID must have a value in order to get the destination GBLOC")
}
+
newGBLOCOconus, err := FetchAddressGbloc(db, *destinationAddress, m.Orders.ServiceMember)
if err != nil {
return "", err
From e25ccab0c96a101dfef1ee0baa4d145962a26d6f Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Mon, 10 Feb 2025 23:11:08 +0000
Subject: [PATCH 31/36] Secondary pickup disabeld
---
src/components/Office/ShipmentForm/ShipmentForm.jsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/components/Office/ShipmentForm/ShipmentForm.jsx b/src/components/Office/ShipmentForm/ShipmentForm.jsx
index dd7480ead49..03e7d006b65 100644
--- a/src/components/Office/ShipmentForm/ShipmentForm.jsx
+++ b/src/components/Office/ShipmentForm/ShipmentForm.jsx
@@ -965,6 +965,7 @@ const ShipmentForm = (props) => {
value="true"
title="Yes, I have a second pickup address"
checked={hasSecondaryPickup === 'true'}
+ disabled={!isPreceedingAddressComplete('true', values.pickup.address)}
/>
{
value="false"
title="No, I do not have a second pickup address"
checked={hasSecondaryPickup !== 'true'}
+ disabled={!isPreceedingAddressComplete('true', values.pickup.address)}
/>
From b9763fb77c1fc409d5e7954e4f7056a723980bd0 Mon Sep 17 00:00:00 2001
From: pambecker
Date: Mon, 10 Feb 2025 19:30:08 -0600
Subject: [PATCH 32/36] check nil
---
pkg/models/move.go | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/pkg/models/move.go b/pkg/models/move.go
index b66ebd3ecc3..236bef5af6b 100644
--- a/pkg/models/move.go
+++ b/pkg/models/move.go
@@ -230,11 +230,15 @@ func (m Move) GetDestinationGBLOC(db *pop.Connection) (string, error) {
return "", errors.WithMessage(ErrInvalidOrderID, "Orders ID must have a value in order to get the destination GBLOC")
}
- newGBLOCOconus, err := FetchAddressGbloc(db, *destinationAddress, m.Orders.ServiceMember)
- if err != nil {
- return "", err
+ if m.Orders.ServiceMember.Affiliation != nil {
+ newGBLOCOconus, err := FetchAddressGbloc(db, *destinationAddress, m.Orders.ServiceMember)
+ if err != nil {
+ return "", err
+ }
+ newGBLOC = *newGBLOCOconus
+ } else {
+ return "", errors.Errorf("ServiceMember.Affiliation cannot be NULL for GetDestinationGBLOC")
}
- newGBLOC = *newGBLOCOconus
} else {
newGBLOCConus, err := FetchGBLOCForPostalCode(db, destinationAddress.PostalCode)
if err != nil {
From 948e79f71293142f29f5ab0e8e421cbf178c2c8c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 11 Feb 2025 11:06:00 +0000
Subject: [PATCH 33/36] Bump distroless/base-debian12 from `ad04bf0` to
`74ddbf5`
Bumps distroless/base-debian12 from `ad04bf0` to `74ddbf5`.
---
updated-dependencies:
- dependency-name: distroless/base-debian12
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
Dockerfile | 2 +-
Dockerfile.dp3 | 2 +-
Dockerfile.local | 2 +-
Dockerfile.migrations | 2 +-
Dockerfile.reviewapp | 2 +-
Dockerfile.tasks | 2 +-
Dockerfile.tasks_dp3 | 2 +-
Dockerfile.tasks_local | 2 +-
8 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index a8353e2dfe5..293ea88db39 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,7 +8,7 @@ RUN apt-get install -y ca-certificates --no-install-recommends
RUN update-ca-certificates
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
COPY --from=build-env /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY bin/rds-ca-rsa4096-g1.pem /bin/rds-ca-rsa4096-g1.pem
diff --git a/Dockerfile.dp3 b/Dockerfile.dp3
index b04ce41a933..c2cafd6bd07 100644
--- a/Dockerfile.dp3
+++ b/Dockerfile.dp3
@@ -1,7 +1,7 @@
FROM harbor.csde.caci.com/docker.io/debian:stable AS build-env
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
#AWS GovCloud RDS cert
COPY bin/rds-ca-rsa4096-g1.pem /bin/rds-ca-rsa4096-g1.pem
diff --git a/Dockerfile.local b/Dockerfile.local
index 93bf4e3edc6..225bb958ab1 100644
--- a/Dockerfile.local
+++ b/Dockerfile.local
@@ -20,7 +20,7 @@ RUN rm -f bin/milmove && make bin/milmove
#########
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
COPY --from=builder --chown=root:root /home/circleci/project/bin/rds-ca-rsa4096-g1.pem /bin/rds-ca-rsa4096-g1.pem
COPY --from=builder --chown=root:root /home/circleci/project/bin/rds-ca-2019-root.pem /bin/rds-ca-2019-root.pem
diff --git a/Dockerfile.migrations b/Dockerfile.migrations
index c0888d1aa60..5d4956df394 100644
--- a/Dockerfile.migrations
+++ b/Dockerfile.migrations
@@ -9,7 +9,7 @@ RUN update-ca-certificates
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
COPY config/tls/dod-wcf-root-ca-1.pem /usr/local/share/ca-certificates/dod-wcf-root-ca-1.pem.crt
COPY config/tls/dod-wcf-intermediate-ca-1.pem /usr/local/share/ca-certificates/dod-wcf-intermediate-ca-1.pem.crt
diff --git a/Dockerfile.reviewapp b/Dockerfile.reviewapp
index 54197570dee..beeb0112195 100644
--- a/Dockerfile.reviewapp
+++ b/Dockerfile.reviewapp
@@ -108,7 +108,7 @@ RUN set -x \
#########
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a as milmove
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348 as milmove
COPY --from=server_builder /build/bin/rds-ca-2019-root.pem /bin/rds-ca-2019-root.pem
COPY --from=server_builder /build/bin/milmove /bin/milmove
diff --git a/Dockerfile.tasks b/Dockerfile.tasks
index 008f518f4ff..d41ee54e808 100644
--- a/Dockerfile.tasks
+++ b/Dockerfile.tasks
@@ -8,7 +8,7 @@ RUN apt-get install -y ca-certificates --no-install-recommends
RUN update-ca-certificates
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
COPY --from=build-env /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY config/tls/milmove-cert-bundle.p7b /config/tls/milmove-cert-bundle.p7b
diff --git a/Dockerfile.tasks_dp3 b/Dockerfile.tasks_dp3
index ab15f0c2e2b..72f71bdb971 100644
--- a/Dockerfile.tasks_dp3
+++ b/Dockerfile.tasks_dp3
@@ -1,5 +1,5 @@
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
# Demo Environment Certs
COPY config/tls/api.demo.dp3.us.chain.der.p7b /config/tls/api.demo.dp3.us.chain.der.p7b
diff --git a/Dockerfile.tasks_local b/Dockerfile.tasks_local
index d4e6dba0c53..bb67bf94872 100644
--- a/Dockerfile.tasks_local
+++ b/Dockerfile.tasks_local
@@ -19,7 +19,7 @@ RUN rm -f bin/milmove-tasks && make bin/milmove-tasks
#########
# hadolint ignore=DL3007
-FROM gcr.io/distroless/base-debian12@sha256:ad04bf079b9ed668d38fe2138cfe575847795985097b38a400f4ef1ff69a561a
+FROM gcr.io/distroless/base-debian12@sha256:74ddbf52d93fafbdd21b399271b0b4aac1babf8fa98cab59e5692e01169a1348
COPY --from=builder --chown=root:root /home/circleci/project/config/tls/milmove-cert-bundle.p7b /config/tls/milmove-cert-bundle.p7b
COPY --from=builder --chown=root:root /home/circleci/project/bin/rds-ca-2019-root.pem /bin/rds-ca-2019-root.pem
From 2c1f2e13fbf1d51c8cec41cdae7f2643b92f8e5a Mon Sep 17 00:00:00 2001
From: Tae Jung
Date: Tue, 11 Feb 2025 15:18:02 +0000
Subject: [PATCH 34/36] refactor
---
.../Office/ServiceItemCalculations/helpers.js | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)
diff --git a/src/components/Office/ServiceItemCalculations/helpers.js b/src/components/Office/ServiceItemCalculations/helpers.js
index ded0b5f0d5f..d555fe17733 100644
--- a/src/components/Office/ServiceItemCalculations/helpers.js
+++ b/src/components/Office/ServiceItemCalculations/helpers.js
@@ -34,19 +34,10 @@ const peak = (params) => {
};
const getMarket = (params) => {
- let marketText = '';
-
- if (getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params)) {
- marketText = ` ${
- getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params)?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'
- }`;
- } else {
- marketText = ` ${
- getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketDest, params)?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'
- }`;
- }
-
- return marketText;
+ const marketValue =
+ getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketOrigin, params) ||
+ getParamValue(SERVICE_ITEM_PARAM_KEYS.MarketDest, params);
+ return ` ${marketValue?.toLowerCase() === 'o' ? 'OCONUS' : 'CONUS'}`;
};
const serviceAreaOrigin = (params) => {
From 54e24affbd71d6537a7766c755d12d146e3443f2 Mon Sep 17 00:00:00 2001
From: Jon Spight
Date: Tue, 11 Feb 2025 16:38:45 +0000
Subject: [PATCH 35/36] fixed conflicts
---
.gitlab-ci.yml | 4 ----
1 file changed, 4 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f5bb39a3581..b374c3819a2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,11 +9,7 @@ variables:
#Docker config
DOCKER_AUTH_CONFIG: "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"$CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD\"}}}"
#hard code sha as newer version of debian is needed for pre-test
-<<<<<<< B-22301-int
DOCKER_APP_IMAGE: milmove01/transcom-docker:milmove-app@sha256:ee774e9244afa2063bbbb7f9b973b17f1f5139366a1b7a676155df0b5268a7e1
-=======
- DOCKER_APP_IMAGE: milmove01/transcom-docker:milmove-app
->>>>>>> integrationTesting
DOCKER_BASE_IMAGE: milmove01/transcom-docker:base
DOCKERHUB_USERNAME: DOCKERHUB_USERNAME
DOCKERHUB_PASSWORD: DOCKERHUB_PASSWORD
From 97fac7f76c42bee2d7a55b2287727ed36bfc1640 Mon Sep 17 00:00:00 2001
From: josiahzimmerman-caci
<147525840+josiahzimmerman-caci@users.noreply.github.com>
Date: Tue, 11 Feb 2025 14:51:07 -0600
Subject: [PATCH 36/36] Update .gitlab-ci.yml
remove sha for intTesting and comment
---
.gitlab-ci.yml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b374c3819a2..1c9ecc29aa2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,8 +8,8 @@
variables:
#Docker config
DOCKER_AUTH_CONFIG: "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"$CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD\"}}}"
- #hard code sha as newer version of debian is needed for pre-test
- DOCKER_APP_IMAGE: milmove01/transcom-docker:milmove-app@sha256:ee774e9244afa2063bbbb7f9b973b17f1f5139366a1b7a676155df0b5268a7e1
+
+ DOCKER_APP_IMAGE: milmove01/transcom-docker:milmove-app
DOCKER_BASE_IMAGE: milmove01/transcom-docker:base
DOCKERHUB_USERNAME: DOCKERHUB_USERNAME
DOCKERHUB_PASSWORD: DOCKERHUB_PASSWORD
@@ -2043,4 +2043,4 @@ deploy_app_prd:
after_script:
- *announce_failure
rules:
- - *check_main
\ No newline at end of file
+ - *check_main