Skip to content

Commit

Permalink
Merge pull request #14450 from transcom/B-21904-NTS-OCONUS-MAIN
Browse files Browse the repository at this point in the history
B 21904 nts oconus main
  • Loading branch information
WeatherfordAaron authored Jan 17, 2025
2 parents adc98a3 + 7fb141d commit 16736fa
Show file tree
Hide file tree
Showing 8 changed files with 378 additions and 55 deletions.
1 change: 1 addition & 0 deletions migrations/app/migrations_manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,7 @@
20241217163231_update_duty_locations_bad_zips.up.sql
20241217180136_add_AK_zips_to_zip3_distances.up.sql
20241218201833_add_PPPO_BASE_ELIZABETH.up.sql
20241218204620_add_international_nts_service_items.up.sql
20241220171035_add_additional_AK_zips_to_zip3_distances.up.sql
20241220213134_add_destination_gbloc_db_function.up.sql
20241224172258_add_and_update_po_box_zip.up.sql
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--
-- Add service items for international NTS shipments.
--
INSERT INTO re_service_items
(id, service_id, shipment_type, market_code, is_auto_approved, created_at, updated_at, sort)
VALUES
--ISLH International Shipping & Linehaul
('2a560507-db09-4be1-b809-49c0f515b31b', '9f3d551a-0725-430e-897e-80ee9add3ae9' ,'HHG_INTO_NTS', 'i', true, now(), now(), 1),
--PODFSC International POD Fuel Surcharge
('e702818f-defd-452c-81a3-865b902e7dd0', '388115e8-abe9-441d-96cf-a39f24baa0a3' ,'HHG_INTO_NTS', 'i', true, now(), now(), 2),
--INPK International NTS packing
('366ee5a4-eb61-4ded-a68c-ddc29fe1a886', '874cb86a-bc39-4f57-a614-53ee3fcacf14' ,'HHG_INTO_NTS', 'i', true, now(), now(), 3),
--ICRT International crating
('aac4e95e-27ed-4f09-9b6b-384d8542f410', '86203d72-7f7c-49ff-82f0-5b95e4958f60' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IDASIT International destination add'l day SIT
('010f2f91-7381-4149-8d74-8eb5f593a864', '806c6d59-57ff-4a3f-9518-ebf29ba9cb10' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IDDSIT International destination SIT delivery
('a41966b7-b83a-4eaf-8e68-d5e884777102', '28389ee1-56cf-400c-aa52-1501ecdd7c69' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IDFSIT International destination 1st day SIT
('14c77957-3c76-465a-bb07-c98d36ef1e54', 'bd6064ca-e780-4ab4-a37b-0ae98eebb244' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IDSHUT International destination shuttle service
('d52d2d03-100a-4ed9-b2de-16eac63a375f', '22fc07ed-be15-4f50-b941-cbd38153b378' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IOASIT International origin add'l day SIT
('7fd91408-7d69-4375-b7e6-5b2ff714206b', 'bd424e45-397b-4766-9712-de4ae3a2da36' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IOFSIT International origin 1st day SIT
('b3dc509d-d652-4300-a702-a1ddce6255b6', 'b488bf85-ea5e-49c8-ba5c-e2fa278ac806' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IOPSIT International origin SIT pickup
('001eadb6-3526-45b9-96e0-0648bb481e86', '6f4f6e31-0675-4051-b659-89832259f390' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IOSHUT International origin shuttle service
('b991c5c9-af2c-4146-b999-1d0bdf91de3f', '624a97c5-dfbf-4da9-a6e9-526b4f95af8d' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IUCRT International uncrating
('5a89315a-257b-4ef0-92cb-4c06aa6f1332', '4132416b-b1aa-42e7-98f2-0ac0a03e8a31' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IOFSC International Origin SIT Fuel Surcharge
('d4a98dea-a5f7-4b92-b5de-e6350ab07824', '81e29d0c-02a6-4a7a-be02-554deb3ee49e' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL),
--IDSFSC International Destination SIT Fuel Surcharge
('eaea90c2-93d3-4db9-89cd-23ac57ec9ce1', '690a5fc1-0ea5-4554-8294-a367b5daefa9' ,'HHG_INTO_NTS', 'i', false, now(), now(), NULL);
6 changes: 5 additions & 1 deletion pkg/factory/mto_shipment_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func buildMTOShipmentWithBuildType(db *pop.Connection, customs []Customization,
defaultStatus = models.MTOShipmentStatusDraft
buildStorageFacility = hasStorageFacilityCustom
shipmentHasPickupDetails = true
shipmentHasDeliveryDetails = false
shipmentHasDeliveryDetails = true
case mtoShipmentNTSR:
defaultShipmentType = models.MTOShipmentTypeHHGOutOfNTS
defaultStatus = models.MTOShipmentStatusDraft
Expand All @@ -83,6 +83,10 @@ func buildMTOShipmentWithBuildType(db *pop.Connection, customs []Customization,
MarketCode: defaultMarketCode,
}

if newMTOShipment.ShipmentType == models.MTOShipmentTypeHHGIntoNTS && newMTOShipment.StorageFacility != nil {
newMTOShipment.DestinationAddress = &newMTOShipment.StorageFacility.Address
}

if cMtoShipment.Status == models.MTOShipmentStatusApproved {
approvedDate := time.Date(GHCTestYear, time.March, 20, 0, 0, 0, 0, time.UTC)
newMTOShipment.ApprovedDate = &approvedDate
Expand Down
4 changes: 2 additions & 2 deletions pkg/factory/mto_shipment_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,9 @@ func (suite *FactorySuite) TestBuildMTOShipment() {
suite.NotNil(ntsShipment.PrimeActualWeight)
suite.Nil(ntsShipment.StorageFacility)
suite.NotNil(ntsShipment.ScheduledPickupDate)
suite.Nil(ntsShipment.RequestedDeliveryDate)
suite.NotNil(ntsShipment.RequestedDeliveryDate)
suite.Nil(ntsShipment.ActualDeliveryDate)
suite.Nil(ntsShipment.ScheduledDeliveryDate)
suite.NotNil(ntsShipment.ScheduledDeliveryDate)
})

suite.Run("Successful creation of NTSShipment with storage facility", func() {
Expand Down
100 changes: 50 additions & 50 deletions pkg/services/mto_shipment/mto_shipment_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -855,8 +855,8 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext,
// we will compare data here to see if we even need to update the pricing
if newShipment.MarketCode == models.MarketCodeInternational &&
(newShipment.PrimeEstimatedWeight != nil ||
newShipment.PickupAddress != nil && newShipment.PickupAddress.PostalCode != dbShipment.PickupAddress.PostalCode ||
newShipment.DestinationAddress != nil && newShipment.DestinationAddress.PostalCode != dbShipment.DestinationAddress.PostalCode ||
newShipment.PickupAddress != nil && dbShipment.PickupAddress != nil && newShipment.PickupAddress.PostalCode != dbShipment.PickupAddress.PostalCode ||
newShipment.DestinationAddress != nil && dbShipment.DestinationAddress != nil && newShipment.DestinationAddress.PostalCode != dbShipment.DestinationAddress.PostalCode ||
newShipment.RequestedPickupDate != nil && newShipment.RequestedPickupDate.Format("2006-01-02") != dbShipment.RequestedPickupDate.Format("2006-01-02")) {

portZip, portType, err := models.GetPortLocationInfoForShipment(appCtx.DB(), newShipment.ID)
Expand Down Expand Up @@ -1110,9 +1110,9 @@ func reServiceCodesForShipment(shipment models.MTOShipment) []models.ReServiceCo
// More info in MB-1140: https://dp3.atlassian.net/browse/MB-1140

// international shipment service items are created in the shipment_approver
switch shipment.ShipmentType {
case models.MTOShipmentTypeHHG:
if shipment.MarketCode != models.MarketCodeInternational {
if shipment.MarketCode != models.MarketCodeInternational {
switch shipment.ShipmentType {
case models.MTOShipmentTypeHHG:
originZIP3 := shipment.PickupAddress.PostalCode[0:3]
destinationZIP3 := shipment.DestinationAddress.PostalCode[0:3]

Expand All @@ -1136,51 +1136,51 @@ func reServiceCodesForShipment(shipment models.MTOShipment) []models.ReServiceCo
models.ReServiceCodeDPK,
models.ReServiceCodeDUPK,
}
}
case models.MTOShipmentTypeHHGIntoNTS:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom NTS Packing
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDNPK,
}
case models.MTOShipmentTypeHHGOutOfNTS:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Unpacking
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDUPK,
}
case models.MTOShipmentTypeMobileHome:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Mobile Home Factor
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDMHF,
}
case models.MTOShipmentTypeBoatHaulAway:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Haul Away Boat Factor
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDBHF,
}
case models.MTOShipmentTypeBoatTowAway:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Tow Away Boat Factor
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDBTF,
case models.MTOShipmentTypeHHGIntoNTS:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom NTS Packing
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDNPK,
}
case models.MTOShipmentTypeHHGOutOfNTS:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Unpacking
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDUPK,
}
case models.MTOShipmentTypeMobileHome:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Mobile Home Factor
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDMHF,
}
case models.MTOShipmentTypeBoatHaulAway:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Haul Away Boat Factor
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDBHF,
}
case models.MTOShipmentTypeBoatTowAway:
// Need to create: Dom Linehaul, Fuel Surcharge, Dom Origin Price, Dom Destination Price, Dom Tow Away Boat Factor
return []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDBTF,
}
}
}

Expand Down
101 changes: 101 additions & 0 deletions pkg/services/mto_shipment/mto_shipment_updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3445,3 +3445,104 @@ func (suite *MTOShipmentServiceSuite) TestUpdateStatusServiceItems() {
suite.Equal(models.ReServiceCodeDSH, serviceItems[0].ReService.Code)
})
}

func (suite *MTOShipmentServiceSuite) TestUpdateDomesticServiceItems() {

expectedReServiceCodes := []models.ReServiceCode{
models.ReServiceCodeDLH,
models.ReServiceCodeFSC,
models.ReServiceCodeDOP,
models.ReServiceCodeDDP,
models.ReServiceCodeDNPK,
}

var pickupAddress models.Address
var storageFacility models.StorageFacility
var mto models.Move

setupTestData := func() {
pickupAddress = factory.BuildAddress(suite.DB(), []factory.Customization{
{
Model: models.Address{
StreetAddress1: "Test Street 1",
City: "Des moines",
State: "IA",
PostalCode: "50309",
IsOconus: models.BoolPointer(false),
},
},
}, nil)

storageFacility = factory.BuildStorageFacility(suite.DB(), []factory.Customization{
{
Model: models.Address{
StreetAddress1: "Test Street Adress 2",
City: "Des moines",
State: "IA",
PostalCode: "50314",
IsOconus: models.BoolPointer(false),
},
},
}, nil)

mto = factory.BuildMove(suite.DB(), []factory.Customization{
{
Model: models.Move{
Status: models.MoveStatusAPPROVED,
},
},
}, nil)
}

builder := query.NewQueryBuilder()
moveRouter := moveservices.NewMoveRouter()
planner := &mocks.Planner{}
planner.On("ZipTransitDistance",
mock.AnythingOfType("*appcontext.appContext"),
mock.Anything,
mock.Anything,
).Return(400, nil)
siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer())
updater := NewMTOShipmentStatusUpdater(builder, siCreator, planner)

suite.Run("Preapproved service items successfully added to domestic nts shipments", func() {
setupTestData()

shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{
{
Model: mto,
LinkOnly: true,
},
{
Model: pickupAddress,
Type: &factory.Addresses.PickupAddress,
LinkOnly: true,
},
{
Model: storageFacility,
Type: &factory.StorageFacility,
LinkOnly: true,
},
{
Model: models.MTOShipment{
ShipmentType: models.MTOShipmentTypeHHGIntoNTS,
Status: models.MTOShipmentStatusSubmitted,
},
},
}, nil)

appCtx := suite.AppContextForTest()
eTag := etag.GenerateEtag(shipment.UpdatedAt)

updatedShipment, err := updater.UpdateMTOShipmentStatus(appCtx, shipment.ID, models.MTOShipmentStatusApproved, nil, nil, eTag)
suite.NoError(err)

serviceItems := models.MTOServiceItems{}
err = appCtx.DB().EagerPreload("ReService").Where("mto_shipment_id = ?", updatedShipment.ID).All(&serviceItems)
suite.NoError(err)

for i := 0; i < len(expectedReServiceCodes); i++ {
suite.Equal(expectedReServiceCodes[i], serviceItems[i].ReService.Code)
}
})
}
4 changes: 3 additions & 1 deletion pkg/services/mto_shipment/shipment_approver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mtoshipment

import (
"math"
"slices"

"github.com/gofrs/uuid"
"github.com/pkg/errors"
Expand Down Expand Up @@ -80,7 +81,8 @@ func (f *shipmentApprover) ApproveShipment(appCtx appcontext.AppContext, shipmen
transactionError := appCtx.NewTransaction(func(txnAppCtx appcontext.AppContext) error {
// create international shipment service items before approving
// we use a database proc to create the basic auto-approved service items
if shipment.ShipmentType == models.MTOShipmentTypeHHG && shipment.MarketCode == models.MarketCodeInternational {
internationalShipmentTypes := []models.MTOShipmentType{models.MTOShipmentTypeHHG, models.MTOShipmentTypeHHGIntoNTS, models.MTOShipmentTypeUnaccompaniedBaggage}
if slices.Contains(internationalShipmentTypes, shipment.ShipmentType) && shipment.MarketCode == models.MarketCodeInternational {
err := models.CreateApprovedServiceItemsForShipment(appCtx.DB(), shipment)
if err != nil {
return err
Expand Down
Loading

0 comments on commit 16736fa

Please sign in to comment.