From e1c92549fd541a0444f45273f8e4610a73614759 Mon Sep 17 00:00:00 2001 From: Steven Gleason <180579696+stevengleason-caci@users.noreply.github.com> Date: Sat, 11 Jan 2025 00:12:58 +0000 Subject: [PATCH 1/2] B-21569 add the service items in their Sort order. Instead of inserting them as we encounter them in the proc, collect them into a temp table, sort them, and then insert. --- migrations/app/migrations_manifest.txt | 1 + ...60244_update_ordering_service_items.up.sql | 203 ++++++++++++++++++ .../mto_shipment/shipment_approver_test.go | 13 +- 3 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 migrations/app/schema/20250110160244_update_ordering_service_items.up.sql diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index a2fde11ae69..221f6b2cffd 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1060,3 +1060,4 @@ 20241227153723_remove_empty_string_emplid_values.up.sql 20241230190638_remove_AK_zips_from_zip3.up.sql 20241230190647_add_missing_AK_zips_to_zip3_distances.up.sql +20250110160244_update_ordering_service_items.up.sql diff --git a/migrations/app/schema/20250110160244_update_ordering_service_items.up.sql b/migrations/app/schema/20250110160244_update_ordering_service_items.up.sql new file mode 100644 index 00000000000..7b5196b9272 --- /dev/null +++ b/migrations/app/schema/20250110160244_update_ordering_service_items.up.sql @@ -0,0 +1,203 @@ +CREATE OR REPLACE PROCEDURE create_approved_service_items_for_shipment( + IN shipment_id UUID +) +AS ' +DECLARE + s_status mto_shipment_status; + s_type mto_shipment_type; + m_code market_code_enum; + move_id UUID; + pickup_address_id UUID; + destination_address_id UUID; + is_pickup_oconus BOOLEAN; + is_destination_oconus BOOLEAN; + service_item RECORD; +BEGIN + -- get shipment type, market code, move_id, and address IDs based on shipment_id + SELECT ms.shipment_type, ms.market_code, ms.move_id, ms.pickup_address_id, ms.destination_address_id, ms.status + INTO s_type, m_code, move_id, pickup_address_id, destination_address_id, s_status + FROM mto_shipments ms + WHERE ms.id = shipment_id; + + IF s_type IS NULL OR m_code IS NULL THEN + RAISE EXCEPTION ''Shipment with ID % not found or missing required details.'', shipment_id; + END IF; + + IF s_status IN (''APPROVED'') THEN + RAISE EXCEPTION ''Shipment with ID % is already in APPROVED status'', shipment_id; + END IF; + + -- get the is_oconus values for both pickup and destination addresses - this determines POD/POE creation + is_pickup_oconus := get_is_oconus(pickup_address_id); + is_destination_oconus := get_is_oconus(destination_address_id); + + -- determine which service item to create based on shipment direction + -- collect the service items into a temporary table for sorting + CREATE TEMPORARY TABLE temp_mto_service_items ( + mto_shipment_id uuid, + move_id uuid, + re_service_id uuid, + service_location service_location_enum, + status service_item_status, + sort text + ) ON COMMIT DROP; + + -- first create the direction-specific service item (POEFSC or PODFSC) + IF is_pickup_oconus AND NOT is_destination_oconus THEN + -- Shipment is OCONUS to CONUS, create PODFSC item + FOR service_item IN + SELECT rsi.id, + rs.id AS re_service_id, + rs.service_location, + rsi.is_auto_approved, + rsi.sort + FROM re_service_items rsi + JOIN re_services rs ON rsi.service_id = rs.id + WHERE rsi.shipment_type = s_type + AND rsi.market_code = m_code + AND rs.code = ''PODFSC'' + AND rsi.is_auto_approved = true + LOOP + BEGIN + IF NOT does_service_item_exist(service_item.re_service_id, shipment_id) THEN + INSERT INTO temp_mto_service_items ( + mto_shipment_id, + move_id, + re_service_id, + service_location, + status, + sort + ) + VALUES ( + shipment_id, + move_id, + service_item.re_service_id, + service_item.service_location, + ''APPROVED''::service_item_status, + service_item.sort + ); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE EXCEPTION ''Error creating PODFSC service item for shipment %: %'', shipment_id, SQLERRM; + END; + END LOOP; + ELSIF NOT is_pickup_oconus AND is_destination_oconus THEN + -- Shipment is CONUS to OCONUS, create POEFSC item + FOR service_item IN + SELECT rsi.id, + rs.id AS re_service_id, + rs.service_location, + rsi.is_auto_approved, + rsi.sort + FROM re_service_items rsi + JOIN re_services rs ON rsi.service_id = rs.id + WHERE rsi.shipment_type = s_type + AND rsi.market_code = m_code + AND rs.code = ''POEFSC'' + AND rsi.is_auto_approved = true + LOOP + BEGIN + IF NOT does_service_item_exist(service_item.re_service_id, shipment_id) THEN + INSERT INTO temp_mto_service_items ( + mto_shipment_id, + move_id, + re_service_id, + service_location, + status, + sort + ) + VALUES ( + shipment_id, + move_id, + service_item.re_service_id, + service_item.service_location, + ''APPROVED''::service_item_status, + service_item.sort + ); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE EXCEPTION ''Error creating POEFSC service item for shipment %: %'', shipment_id, SQLERRM; + END; + END LOOP; + END IF; + + -- create all other auto-approved service items, filtering out the POEFSC or PODFSC service items + FOR service_item IN + SELECT rsi.id, + rs.id AS re_service_id, + rs.service_location, + rsi.is_auto_approved, + rsi.sort + FROM re_service_items rsi + JOIN re_services rs ON rsi.service_id = rs.id + WHERE rsi.shipment_type = s_type + AND rsi.market_code = m_code + AND rsi.is_auto_approved = true + AND rs.code NOT IN (''POEFSC'', ''PODFSC'') + LOOP + BEGIN + IF NOT does_service_item_exist(service_item.re_service_id, shipment_id) THEN + INSERT INTO temp_mto_service_items ( + mto_shipment_id, + move_id, + re_service_id, + service_location, + status, + sort + ) + VALUES ( + shipment_id, + move_id, + service_item.re_service_id, + service_item.service_location, + ''APPROVED''::service_item_status, + service_item.sort + ); + End IF; + EXCEPTION + WHEN OTHERS THEN + RAISE EXCEPTION ''Error creating other service item for shipment %: %'', shipment_id, SQLERRM; + END; + END LOOP; + + -- Insert the mto_service_items in order + FOR service_item IN + SELECT tmsi.mto_shipment_id, + tmsi.move_id, + tmsi.re_service_id, + tmsi.service_location, + tmsi.status + FROM temp_mto_service_items tmsi + ORDER BY sort + LOOP + BEGIN + INSERT INTO mto_service_items ( + mto_shipment_id, + move_id, + re_service_id, + service_location, + status, + created_at, + updated_at, + approved_at + ) + VALUES ( + service_item.mto_shipment_id, + service_item.move_id, + service_item.re_service_id, + service_item.service_location, + service_item.status, + NOW(), + NOW(), + NOW() + ); + EXCEPTION + WHEN OTHERS THEN + RAISE EXCEPTION ''Error creating service items from temp table for shipment %: %'', shipment_id, SQLERRM; + END; + END LOOP; +END; +' +LANGUAGE plpgsql; diff --git a/pkg/services/mto_shipment/shipment_approver_test.go b/pkg/services/mto_shipment/shipment_approver_test.go index 886aea6f3f9..cca893524d9 100644 --- a/pkg/services/mto_shipment/shipment_approver_test.go +++ b/pkg/services/mto_shipment/shipment_approver_test.go @@ -836,15 +836,14 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { expectedReserviceCodes := []models.ReServiceCode{ models.ReServiceCodeUBP, + models.ReServiceCodePOEFSC, models.ReServiceCodeIUBPK, models.ReServiceCodeIUBUPK, - models.ReServiceCodePOEFSC, } suite.Equal(4, len(serviceItems)) for i := 0; i < len(serviceItems); i++ { - actualReServiceCode := serviceItems[i].ReService.Code - suite.True(slices.Contains(expectedReserviceCodes, actualReServiceCode), "Contains unexpected: "+actualReServiceCode.String()) + suite.Equal(expectedReserviceCodes[i], serviceItems[i].ReService.Code) } }) @@ -896,15 +895,14 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { expectedReserviceCodes := []models.ReServiceCode{ models.ReServiceCodeUBP, + models.ReServiceCodePODFSC, models.ReServiceCodeIUBPK, models.ReServiceCodeIUBUPK, - models.ReServiceCodePODFSC, } suite.Equal(4, len(serviceItems)) for i := 0; i < len(serviceItems); i++ { - actualReServiceCode := serviceItems[i].ReService.Code - suite.True(slices.Contains(expectedReserviceCodes, actualReServiceCode), "Contains unexpected: "+actualReServiceCode.String()) + suite.Equal(expectedReserviceCodes[i], serviceItems[i].ReService.Code) } }) @@ -962,8 +960,7 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { suite.Equal(3, len(serviceItems)) for i := 0; i < len(serviceItems); i++ { - actualReServiceCode := serviceItems[i].ReService.Code - suite.True(slices.Contains(expectedReserviceCodes, actualReServiceCode), "Contains unexpected: "+actualReServiceCode.String()) + suite.Equal(expectedReserviceCodes[i], serviceItems[i].ReService.Code) } }) From 1c962448ecb08d39cda3a2b643acc31bec467b8b Mon Sep 17 00:00:00 2001 From: Steven Gleason <180579696+stevengleason-caci@users.noreply.github.com> Date: Mon, 13 Jan 2025 19:47:01 +0000 Subject: [PATCH 2/2] B-21569 rename UBP to "International UB price", from just "International UB". --- migrations/app/migrations_manifest.txt | 1 + .../schema/20250113152050_rename_ubp.up.sql | 1 + pkg/models/re_service.go | 2 +- .../mto_shipment/shipment_approver_test.go | 32 +++++++++++++++---- .../ShipmentServiceItemsTable.test.jsx | 8 ++--- 5 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 migrations/app/schema/20250113152050_rename_ubp.up.sql diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index 221f6b2cffd..0d5a220354b 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1061,3 +1061,4 @@ 20241230190638_remove_AK_zips_from_zip3.up.sql 20241230190647_add_missing_AK_zips_to_zip3_distances.up.sql 20250110160244_update_ordering_service_items.up.sql +20250113152050_rename_ubp.up.sql diff --git a/migrations/app/schema/20250113152050_rename_ubp.up.sql b/migrations/app/schema/20250113152050_rename_ubp.up.sql new file mode 100644 index 00000000000..41a5f532193 --- /dev/null +++ b/migrations/app/schema/20250113152050_rename_ubp.up.sql @@ -0,0 +1 @@ +update re_services set name = 'International UB price' where code = 'UBP'; \ No newline at end of file diff --git a/pkg/models/re_service.go b/pkg/models/re_service.go index 5fc9d9b3e75..75d62317f1c 100644 --- a/pkg/models/re_service.go +++ b/pkg/models/re_service.go @@ -119,7 +119,7 @@ const ( ReServiceCodeNSTH ReServiceCode = "NSTH" // ReServiceCodeNSTUB Nonstandard UB ReServiceCodeNSTUB ReServiceCode = "NSTUB" - // ReServiceCodeUBP International UB + // ReServiceCodeUBP International UB price ReServiceCodeUBP ReServiceCode = "UBP" // ReServiceCodeISLH Shipping & Linehaul ReServiceCodeISLH ReServiceCode = "ISLH" diff --git a/pkg/services/mto_shipment/shipment_approver_test.go b/pkg/services/mto_shipment/shipment_approver_test.go index cca893524d9..aef6158ddc1 100644 --- a/pkg/services/mto_shipment/shipment_approver_test.go +++ b/pkg/services/mto_shipment/shipment_approver_test.go @@ -834,16 +834,23 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { err2 := suite.AppContextForTest().DB().EagerPreload("ReService").Where("mto_shipment_id = ?", internationalShipment.ID).Order("created_at asc").All(&serviceItems) suite.NoError(err2) - expectedReserviceCodes := []models.ReServiceCode{ + expectedReServiceCodes := []models.ReServiceCode{ models.ReServiceCodeUBP, models.ReServiceCodePOEFSC, models.ReServiceCodeIUBPK, models.ReServiceCodeIUBUPK, } + expectedReServiceNames := []string{ + "International UB price", + "International POE Fuel Surcharge", + "International UB pack", + "International UB unpack", + } suite.Equal(4, len(serviceItems)) for i := 0; i < len(serviceItems); i++ { - suite.Equal(expectedReserviceCodes[i], serviceItems[i].ReService.Code) + suite.Equal(expectedReServiceCodes[i], serviceItems[i].ReService.Code) + suite.Equal(expectedReServiceNames[i], serviceItems[i].ReService.Name) } }) @@ -893,16 +900,23 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { err2 := suite.AppContextForTest().DB().EagerPreload("ReService").Where("mto_shipment_id = ?", internationalShipment.ID).Order("created_at asc").All(&serviceItems) suite.NoError(err2) - expectedReserviceCodes := []models.ReServiceCode{ + expectedReServiceCodes := []models.ReServiceCode{ models.ReServiceCodeUBP, models.ReServiceCodePODFSC, models.ReServiceCodeIUBPK, models.ReServiceCodeIUBUPK, } + expectedReServiceNames := []string{ + "International UB price", + "International POD Fuel Surcharge", + "International UB pack", + "International UB unpack", + } suite.Equal(4, len(serviceItems)) for i := 0; i < len(serviceItems); i++ { - suite.Equal(expectedReserviceCodes[i], serviceItems[i].ReService.Code) + suite.Equal(expectedReServiceCodes[i], serviceItems[i].ReService.Code) + suite.Equal(expectedReServiceNames[i], serviceItems[i].ReService.Name) } }) @@ -952,15 +966,21 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { err2 := suite.AppContextForTest().DB().EagerPreload("ReService").Where("mto_shipment_id = ?", internationalShipment.ID).Order("created_at asc").All(&serviceItems) suite.NoError(err2) - expectedReserviceCodes := []models.ReServiceCode{ + expectedReServiceCodes := []models.ReServiceCode{ models.ReServiceCodeUBP, models.ReServiceCodeIUBPK, models.ReServiceCodeIUBUPK, } + expectedReServiceNames := []string{ + "International UB price", + "International UB pack", + "International UB unpack", + } suite.Equal(3, len(serviceItems)) for i := 0; i < len(serviceItems); i++ { - suite.Equal(expectedReserviceCodes[i], serviceItems[i].ReService.Code) + suite.Equal(expectedReServiceCodes[i], serviceItems[i].ReService.Code) + suite.Equal(expectedReServiceNames[i], serviceItems[i].ReService.Name) } }) diff --git a/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx b/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx index 9b18298293b..592ae52467a 100644 --- a/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx +++ b/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx @@ -25,7 +25,7 @@ const reServiceItemResponse = [ isAutoApproved: true, marketCode: 'i', serviceCode: 'UBP', - serviceName: 'International UB', + serviceName: 'International UB price', shipmentType: 'UNACCOMPANIED_BAGGAGE', }, { @@ -370,7 +370,7 @@ describe('Shipment Service Items Table', () => { describe('renders the intl UB shipment type (CONUS -> OCONUS) with service items', () => { it.each([ - ['International UB'], + ['International UB price'], ['International POE Fuel Surcharge'], ['International UB pack'], ['International UB unpack'], @@ -385,7 +385,7 @@ describe('Shipment Service Items Table', () => { describe('renders the intl UB shipment type (OCONUS -> CONUS) with service items', () => { it.each([ - ['International UB'], + ['International UB price'], ['International POD Fuel Surcharge'], ['International UB pack'], ['International UB unpack'], @@ -399,7 +399,7 @@ describe('Shipment Service Items Table', () => { }); describe('renders the intl UB shipment type (OCONUS -> OCONUS) with service items', () => { - it.each([['International UB'], ['International UB pack'], ['International UB unpack']])( + it.each([['International UB price'], ['International UB pack'], ['International UB unpack']])( 'expects %s to be in the document', async (serviceItem) => { render();