Skip to content

Commit

Permalink
Merge pull request #14579 from transcom/B-21557-INT-Estimated-Price
Browse files Browse the repository at this point in the history
B 21557 INT Update Estimated prices for NTS-R Service items on "Previously Recorded Weight" Update
  • Loading branch information
joeydoyecaci authored Jan 24, 2025
2 parents 6c69f1c + a79af19 commit 36cd071
Show file tree
Hide file tree
Showing 14 changed files with 311 additions and 69 deletions.
4 changes: 2 additions & 2 deletions pkg/handlers/ghcapi/mto_service_items.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (h UpdateServiceItemSitEntryDateHandler) Handle(params mtoserviceitemop.Upd

existingETag := etag.GenerateEtag(shipment.UpdatedAt)

shipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc", nil)
shipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc")
if err != nil {
appCtx.Logger().Error(fmt.Sprintf("Could not update the shipment SIT auth end date for shipment ID: %s: %s", shipment.ID, err))
}
Expand Down Expand Up @@ -266,7 +266,7 @@ func (h UpdateMTOServiceItemStatusHandler) Handle(params mtoserviceitemop.Update

existingETag := etag.GenerateEtag(shipment.UpdatedAt)

shipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc", nil)
shipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc")
if err != nil {
appCtx.Logger().Error(fmt.Sprintf("Could not update the shipment SIT auth end date for shipment ID: %s: %s", shipment.ID, err))
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/handlers/ghcapi/mto_shipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ func (h UpdateShipmentHandler) Handle(params mtoshipmentops.UpdateMTOShipmentPar
mtoShipment.PrimeEstimatedWeight = &previouslyRecordedWeight
}

updatedMtoShipment, err := h.ShipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "ghc", nil)
updatedMtoShipment, err := h.ShipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "ghc")
if err != nil {
return handleError(err)
}
Expand Down Expand Up @@ -1124,7 +1124,7 @@ func (h ApproveSITExtensionHandler) Handle(params shipmentops.ApproveSITExtensio

existingETag := etag.GenerateEtag(updatedShipment.UpdatedAt)

updatedShipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc", nil)
updatedShipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc")
if err != nil {
return handleError(err)
}
Expand Down Expand Up @@ -1371,7 +1371,7 @@ func (h CreateApprovedSITDurationUpdateHandler) Handle(params shipmentops.Create

existingETag := etag.GenerateEtag(shipment.UpdatedAt)

shipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc", nil)
shipment, err = h.UpdateShipment(appCtx, &shipmentWithSITInfo, existingETag, "ghc")
if err != nil {
return handleError(err)
}
Expand Down
1 change: 0 additions & 1 deletion pkg/handlers/ghcapi/mto_shipment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4655,7 +4655,6 @@ func (suite *HandlerSuite) TestUpdateShipmentHandler() {
mock.Anything,
mock.Anything,
mock.Anything,
nil,
).Return(nil, err)

oldShipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{
Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/internalapi/mto_shipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (h UpdateMTOShipmentHandler) Handle(params mtoshipmentops.UpdateMTOShipment
h.GetTraceIDFromRequest(params.HTTPRequest))), invalidShipmentStatusErr
}

updatedMTOShipment, err := h.shipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "internal", nil)
updatedMTOShipment, err := h.shipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "internal")

if err != nil {
appCtx.Logger().Error("internalapi.UpdateMTOShipmentHandler", zap.Error(err))
Expand Down
1 change: 0 additions & 1 deletion pkg/handlers/internalapi/mto_shipment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1487,7 +1487,6 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentHandler() {
mock.AnythingOfType("*models.MTOShipment"),
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
nil,
).Return(nil, err)

subtestData := getDefaultMTOShipmentAndParams(&mockUpdater)
Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/primeapiv2/mto_shipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func (h UpdateMTOShipmentHandler) Handle(params mtoshipmentops.UpdateMTOShipment
mtoShipment.ShipmentType = dbShipment.ShipmentType

appCtx.Logger().Info("primeapi.UpdateMTOShipmentHandler info", zap.String("pointOfContact", params.Body.PointOfContact))
mtoShipment, err = h.ShipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "prime-v2", h.planner)
mtoShipment, err = h.ShipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "prime-v2")
if err != nil {
appCtx.Logger().Error("primeapi.UpdateMTOShipmentHandler error", zap.Error(err))
switch e := err.(type) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/primeapiv3/mto_shipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (h UpdateMTOShipmentHandler) Handle(params mtoshipmentops.UpdateMTOShipment
mtoShipment.ShipmentType = dbShipment.ShipmentType

appCtx.Logger().Info("primeapi.UpdateMTOShipmentHandler info", zap.String("pointOfContact", params.Body.PointOfContact))
mtoShipment, err = h.ShipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "prime-v3", h.planner)
mtoShipment, err = h.ShipmentUpdater.UpdateShipment(appCtx, mtoShipment, params.IfMatch, "prime-v3")
if err != nil {
appCtx.Logger().Error("primeapi.UpdateMTOShipmentHandler error", zap.Error(err))
switch e := err.(type) {
Expand Down
20 changes: 9 additions & 11 deletions pkg/services/mocks/ShipmentUpdater.go

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

44 changes: 31 additions & 13 deletions pkg/services/mto_service_item/mto_service_item_creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type mtoServiceItemCreator struct {
fuelSurchargePricer services.FuelSurchargePricer
}

// FindEstimatedPrice finds the estimated price for a service item
func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, mtoShipment models.MTOShipment) (unit.Cents, error) {
if serviceItem.ReService.Code == models.ReServiceCodeDOP ||
serviceItem.ReService.Code == models.ReServiceCodeDPK ||
Expand All @@ -55,11 +56,8 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
requestedPickupDate := *mtoShipment.RequestedPickupDate
currTime := time.Now()
var distance int
primeEstimatedWeight := mtoShipment.PrimeEstimatedWeight
if mtoShipment.ShipmentType == models.MTOShipmentTypeHHGOutOfNTS {
newWeight := int(primeEstimatedWeight.Float64() * 1.1)
primeEstimatedWeight = (*unit.Pound)(&newWeight)
}

adjustedWeight := GetAdjustedWeight(*mtoShipment.PrimeEstimatedWeight, mtoShipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage)

contractCode, err := FetchContractCode(appCtx, currTime)
if err != nil {
Expand All @@ -78,7 +76,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
return 0, err
}

price, _, err = o.originPricer.Price(appCtx, contractCode, requestedPickupDate, *primeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM)
price, _, err = o.originPricer.Price(appCtx, contractCode, requestedPickupDate, *adjustedWeight, domesticServiceArea.ServiceArea, isPPM)
if err != nil {
return 0, err
}
Expand All @@ -91,7 +89,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,

servicesScheduleOrigin := domesticServiceArea.ServicesSchedule

price, _, err = o.packPricer.Price(appCtx, contractCode, requestedPickupDate, *primeEstimatedWeight, servicesScheduleOrigin, isPPM)
price, _, err = o.packPricer.Price(appCtx, contractCode, requestedPickupDate, *adjustedWeight, servicesScheduleOrigin, isPPM)
if err != nil {
return 0, err
}
Expand All @@ -106,7 +104,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
}
}

price, _, err = o.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, *primeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM)
price, _, err = o.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, *adjustedWeight, domesticServiceArea.ServiceArea, isPPM)
if err != nil {
return 0, err
}
Expand All @@ -119,7 +117,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,

serviceScheduleDestination := domesticServiceArea.ServicesSchedule

price, _, err = o.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *primeEstimatedWeight, serviceScheduleDestination, isPPM)
price, _, err = o.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *adjustedWeight, serviceScheduleDestination, isPPM)
if err != nil {
return 0, err
}
Expand All @@ -137,7 +135,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
return 0, err
}
}
price, _, err = o.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *primeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM)
price, _, err = o.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *adjustedWeight, domesticServiceArea.ServiceArea, isPPM)
if err != nil {
return 0, err
}
Expand All @@ -153,7 +151,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
return 0, err
}
}
price, _, err = o.shorthaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *primeEstimatedWeight, domesticServiceArea.ServiceArea)
price, _, err = o.shorthaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *adjustedWeight, domesticServiceArea.ServiceArea)
if err != nil {
return 0, err
}
Expand All @@ -177,7 +175,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
}
}

fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, *primeEstimatedWeight)
fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, *adjustedWeight)
if err != nil {
return 0, err
}
Expand All @@ -189,7 +187,7 @@ func (o *mtoServiceItemCreator) FindEstimatedPrice(appCtx appcontext.AppContext,
if err != nil {
return 0, err
}
price, _, err = o.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), *primeEstimatedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM)
price, _, err = o.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), *adjustedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM)
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -608,6 +606,7 @@ func (o *mtoServiceItemCreator) CreateMTOServiceItem(appCtx appcontext.AppContex
// if estimated weight for shipment provided by the prime, calculate the estimated prices for
// DLH, DPK, DOP, DDP, DUPK

// NTS-release requested pickup dates are for handle out, their pricing is handled differently as their locations are based on storage facilities, not pickup locations
if mtoShipment.PrimeEstimatedWeight != nil && mtoShipment.RequestedPickupDate != nil {
serviceItemEstimatedPrice, err := o.FindEstimatedPrice(appCtx, serviceItem, mtoShipment)
if serviceItemEstimatedPrice != 0 && err == nil {
Expand Down Expand Up @@ -940,3 +939,22 @@ func (o *mtoServiceItemCreator) validateFirstDaySITServiceItem(appCtx appcontext

return &extraServiceItems, nil
}

// Get Adjusted weight for pricing. Returns the weight at 110% or the minimum billable weight whichever is higher, unless it's 0
func GetAdjustedWeight(incomingWeight unit.Pound, isUB bool) *unit.Pound {
// minimum weight billed by GHC is 500 lbs unless it's Unaccompanied Baggage (UB)
minimumBilledWeight := unit.Pound(500)
if isUB {
minimumBilledWeight = unit.Pound(300)
}

// add 110% modifier to billable weight
newWeight := (int(incomingWeight.Float64() * 1.1))
adjustedWeight := (*unit.Pound)(&newWeight)

// if the adjusted weight is less than the minimum billable weight but is nonzero, set it to the minimum weight billed
if *adjustedWeight < minimumBilledWeight && *adjustedWeight > 0 {
*adjustedWeight = minimumBilledWeight
}
return adjustedWeight
}
75 changes: 69 additions & 6 deletions pkg/services/mto_service_item/mto_service_item_creator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2108,22 +2108,22 @@ func (suite *MTOServiceItemServiceSuite) TestPriceEstimator() {
creator := NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer())

dopEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemDOP, shipment)
suite.Equal(unit.Cents(61080), dopEstimatedPriceInCents)
suite.Equal(unit.Cents(67188), dopEstimatedPriceInCents)

dpkEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemDPK, shipment)
suite.Equal(unit.Cents(540000), dpkEstimatedPriceInCents)
suite.Equal(unit.Cents(594000), dpkEstimatedPriceInCents)

ddpEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemDDP, shipment)
suite.Equal(unit.Cents(42240), ddpEstimatedPriceInCents)
suite.Equal(unit.Cents(46464), ddpEstimatedPriceInCents)

dupkEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemDUPK, shipment)
suite.Equal(unit.Cents(43860), dupkEstimatedPriceInCents)
suite.Equal(unit.Cents(48246), dupkEstimatedPriceInCents)

dlhEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemDLH, shipment)
suite.Equal(unit.Cents(12381600), dlhEstimatedPriceInCents)
suite.Equal(unit.Cents(13619760), dlhEstimatedPriceInCents)

dshEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemDSH, shipment)
suite.Equal(unit.Cents(10080000), dshEstimatedPriceInCents)
suite.Equal(unit.Cents(11088000), dshEstimatedPriceInCents)

fscEstimatedPriceInCents, _ := creator.FindEstimatedPrice(suite.AppContextForTest(), &serviceItemFSC, shipment)
suite.Equal(unit.Cents(-168), fscEstimatedPriceInCents)
Expand Down Expand Up @@ -2429,3 +2429,66 @@ func (suite *MTOServiceItemServiceSuite) TestPriceEstimator() {
})

}
func (suite *MTOServiceItemServiceSuite) TestGetAdjustedWeight() {
suite.Run("If no weight is provided", func() {
var incomingWeight unit.Pound
adjustedWeight := GetAdjustedWeight(incomingWeight, false)
suite.Equal(unit.Pound(0), *adjustedWeight)
})
suite.Run("If a weight of 0 is provided", func() {
incomingWeight := unit.Pound(0)
adjustedWeight := GetAdjustedWeight(incomingWeight, false)
suite.Equal(unit.Pound(0), *adjustedWeight)
})
suite.Run("If weight of 100 is provided", func() {
incomingWeight := unit.Pound(100)
adjustedWeight := GetAdjustedWeight(incomingWeight, false)
suite.Equal(unit.Pound(500), *adjustedWeight)
})
suite.Run("If weight of 454 is provided", func() {
incomingWeight := unit.Pound(454)
adjustedWeight := GetAdjustedWeight(incomingWeight, false)
suite.Equal(unit.Pound(500), *adjustedWeight)
})
suite.Run("If weight of 456 is provided", func() {
incomingWeight := unit.Pound(456)
adjustedWeight := GetAdjustedWeight(incomingWeight, false)
suite.Equal(unit.Pound(501), *adjustedWeight)
})
suite.Run("If weight of 1000 is provided", func() {
incomingWeight := unit.Pound(1000)
adjustedWeight := GetAdjustedWeight(incomingWeight, false)
suite.Equal(unit.Pound(1100), *adjustedWeight)
})

suite.Run("If no weight is provided UB", func() {
var incomingWeight unit.Pound
adjustedWeight := GetAdjustedWeight(incomingWeight, true)
suite.Equal(unit.Pound(0), *adjustedWeight)
})
suite.Run("If a weight of 0 is provided UB", func() {
incomingWeight := unit.Pound(0)
adjustedWeight := GetAdjustedWeight(incomingWeight, true)
suite.Equal(unit.Pound(0), *adjustedWeight)
})
suite.Run("If weight of 100 is provided UB", func() {
incomingWeight := unit.Pound(100)
adjustedWeight := GetAdjustedWeight(incomingWeight, true)
suite.Equal(unit.Pound(300), *adjustedWeight)
})
suite.Run("If weight of 272 is provided UB", func() {
incomingWeight := unit.Pound(272)
adjustedWeight := GetAdjustedWeight(incomingWeight, true)
suite.Equal(unit.Pound(300), *adjustedWeight)
})
suite.Run("If weight of 274 is provided UB", func() {
incomingWeight := unit.Pound(274)
adjustedWeight := GetAdjustedWeight(incomingWeight, true)
suite.Equal(unit.Pound(301), *adjustedWeight)
})
suite.Run("If weight of 1000 is provided UB", func() {
incomingWeight := unit.Pound(1000)
adjustedWeight := GetAdjustedWeight(incomingWeight, true)
suite.Equal(unit.Pound(1100), *adjustedWeight)
})
}
1 change: 0 additions & 1 deletion pkg/services/mto_shipment/mto_shipment_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,6 @@ 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{
Expand Down
Loading

0 comments on commit 36cd071

Please sign in to comment.