From f27f3ebe907501aed7806a90f0b4cc1ccc8f64b7 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Tue, 12 Nov 2024 14:20:55 -0600 Subject: [PATCH 01/19] Approving destination address change will update service item pricing --- pkg/handlers/ghcapi/api.go | 4 +- pkg/handlers/ghcapi/mto_service_items_test.go | 4 +- pkg/handlers/ghcapi/mto_shipment_test.go | 4 +- pkg/handlers/primeapi/api.go | 2 +- .../primeapi/mto_service_item_test.go | 4 +- pkg/handlers/supportapi/api.go | 2 +- .../supportapi/mto_service_item_test.go | 7 +- pkg/services/mocks/MTOServiceItemUpdater.go | 30 ++++ .../move_history/move_history_fetcher_test.go | 2 +- pkg/services/mto_service_item.go | 1 + .../mto_service_item_updater.go | 154 +++++++++++++++++- .../mto_service_item_updater_test.go | 5 +- .../mto_service_item_validators.go | 3 + .../shipment_address_update_requester.go | 36 +++- .../sit_extension/sit_extension_denier.go | 3 +- pkg/testdatagen/scenario/shared.go | 6 +- 16 files changed, 236 insertions(+), 31 deletions(-) diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index 5d20500500e..47fd3176180 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -231,7 +231,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { ghcAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{ HandlerConfig: handlerConfig, - MTOServiceItemUpdater: mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator), + MTOServiceItemUpdater: mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), Fetcher: fetch.NewFetcher(queryBuilder), ShipmentSITStatus: sitstatus.NewShipmentSITStatus(), MTOShipmentFetcher: mtoshipment.NewMTOShipmentFetcher(), @@ -501,7 +501,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { ghcAPI.ShipmentUpdateSITServiceItemCustomerExpenseHandler = UpdateSITServiceItemCustomerExpenseHandler{ handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator), + mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), mtoshipment.NewMTOShipmentFetcher(), shipmentSITStatus, } diff --git a/pkg/handlers/ghcapi/mto_service_items_test.go b/pkg/handlers/ghcapi/mto_service_items_test.go index 3b0b3e74d1b..8ba2ab744bd 100644 --- a/pkg/handlers/ghcapi/mto_service_items_test.go +++ b/pkg/handlers/ghcapi/mto_service_items_test.go @@ -563,7 +563,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator) + mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) handler := UpdateMTOServiceItemStatusHandler{ HandlerConfig: suite.HandlerConfig(), @@ -623,7 +623,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator) + mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) handler := UpdateMTOServiceItemStatusHandler{ HandlerConfig: suite.HandlerConfig(), diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index aa96acd49f0..5cc9d43ebe8 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -4674,7 +4674,7 @@ func (suite *HandlerSuite) TestUpdateSITServiceItemCustomerExpenseHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator) + updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) req := httptest.NewRequest("PATCH", fmt.Sprintf("/shipments/%s/sit-service-item/convert-to-customer-expense", approvedShipment.ID.String()), nil) req = suite.AuthenticateOfficeRequest(req, officeUser) handlerConfig := suite.HandlerConfig() @@ -4750,7 +4750,7 @@ func (suite *HandlerSuite) TestUpdateSITServiceItemCustomerExpenseHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator) + updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) req := httptest.NewRequest("PATCH", fmt.Sprintf("/shipments/%s/sit-service-item/convert-to-customer-expense", approvedShipment.ID.String()), nil) req = suite.AuthenticateOfficeRequest(req, officeUser) handlerConfig := suite.HandlerConfig() diff --git a/pkg/handlers/primeapi/api.go b/pkg/handlers/primeapi/api.go index b614fb13d60..25afdb43b77 100644 --- a/pkg/handlers/primeapi/api.go +++ b/pkg/handlers/primeapi/api.go @@ -45,7 +45,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP shipmentFetcher := mtoshipment.NewMTOShipmentFetcher() moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()) uploadCreator := upload.NewUploadCreator(handlerConfig.FileStorer()) - serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator) + serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) userUploader, err := uploader.NewUserUploader(handlerConfig.FileStorer(), uploader.MaxCustomerUserUploadFileSizeLimit) if err != nil { diff --git a/pkg/handlers/primeapi/mto_service_item_test.go b/pkg/handlers/primeapi/mto_service_item_test.go index b635bb4d124..cf2e636495e 100644 --- a/pkg/handlers/primeapi/mto_service_item_test.go +++ b/pkg/handlers/primeapi/mto_service_item_test.go @@ -1543,7 +1543,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemDDDSIT() { ).Return(400, nil) subtestData.handler = UpdateMTOServiceItemHandler{ suite.HandlerConfig(), - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), } // create the params struct @@ -1825,7 +1825,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemDOPSIT() { ).Return(400, nil) subtestData.handler = UpdateMTOServiceItemHandler{ suite.HandlerConfig(), - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), } // create the params struct diff --git a/pkg/handlers/supportapi/api.go b/pkg/handlers/supportapi/api.go index dd2a5df8b8f..1aba70b9c72 100644 --- a/pkg/handlers/supportapi/api.go +++ b/pkg/handlers/supportapi/api.go @@ -88,7 +88,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler { mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), handlerConfig.HHGPlanner()), } - supportAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{handlerConfig, mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator)} + supportAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{handlerConfig, mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer())} supportAPI.WebhookReceiveWebhookNotificationHandler = ReceiveWebhookNotificationHandler{handlerConfig} // Create TAC and LOA services diff --git a/pkg/handlers/supportapi/mto_service_item_test.go b/pkg/handlers/supportapi/mto_service_item_test.go index 44a56716688..5db466e8d52 100644 --- a/pkg/handlers/supportapi/mto_service_item_test.go +++ b/pkg/handlers/supportapi/mto_service_item_test.go @@ -22,6 +22,7 @@ import ( "github.com/transcom/mymove/pkg/models" routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services/address" + "github.com/transcom/mymove/pkg/services/ghcrateengine" moverouter "github.com/transcom/mymove/pkg/services/move" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" @@ -85,7 +86,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandlerApproveSuccess() mock.Anything, ).Return(400, nil) handler := UpdateMTOServiceItemStatusHandler{handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), } // CALL FUNCTION UNDER TEST @@ -141,7 +142,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandlerRejectSuccess() mock.Anything, ).Return(400, nil) handler := UpdateMTOServiceItemStatusHandler{handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), } // CALL FUNCTION UNDER TEST @@ -197,7 +198,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandlerRejectionFailedN mock.Anything, ).Return(400, nil) handler := UpdateMTOServiceItemStatusHandler{handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), } // CALL FUNCTION UNDER TEST diff --git a/pkg/services/mocks/MTOServiceItemUpdater.go b/pkg/services/mocks/MTOServiceItemUpdater.go index ed356fd7699..bbb6bd86828 100644 --- a/pkg/services/mocks/MTOServiceItemUpdater.go +++ b/pkg/services/mocks/MTOServiceItemUpdater.go @@ -138,6 +138,36 @@ func (_m *MTOServiceItemUpdater) UpdateMTOServiceItemBasic(appCtx appcontext.App return r0, r1 } +// UpdateMTOServiceItemPricingEstimate provides a mock function with given fields: appCtx, serviceItem, shipment, eTag +func (_m *MTOServiceItemUpdater) UpdateMTOServiceItemPricingEstimate(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, shipment models.MTOShipment, eTag string) (*models.MTOServiceItem, error) { + ret := _m.Called(appCtx, serviceItem, shipment, eTag) + + if len(ret) == 0 { + panic("no return value specified for UpdateMTOServiceItemPricingEstimate") + } + + var r0 *models.MTOServiceItem + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, *models.MTOServiceItem, models.MTOShipment, string) (*models.MTOServiceItem, error)); ok { + return rf(appCtx, serviceItem, shipment, eTag) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, *models.MTOServiceItem, models.MTOShipment, string) *models.MTOServiceItem); ok { + r0 = rf(appCtx, serviceItem, shipment, eTag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.MTOServiceItem) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, *models.MTOServiceItem, models.MTOShipment, string) error); ok { + r1 = rf(appCtx, serviceItem, shipment, eTag) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // UpdateMTOServiceItemPrime provides a mock function with given fields: appCtx, serviceItem, planner, shipment, eTag func (_m *MTOServiceItemUpdater) UpdateMTOServiceItemPrime(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, planner route.Planner, shipment models.MTOShipment, eTag string) (*models.MTOServiceItem, error) { ret := _m.Called(appCtx, serviceItem, planner, shipment, eTag) diff --git a/pkg/services/move_history/move_history_fetcher_test.go b/pkg/services/move_history/move_history_fetcher_test.go index 13b85471c12..fef04459564 100644 --- a/pkg/services/move_history/move_history_fetcher_test.go +++ b/pkg/services/move_history/move_history_fetcher_test.go @@ -374,7 +374,7 @@ func (suite *MoveHistoryServiceSuite) TestMoveHistoryFetcherScenarios() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator) + updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) move := factory.BuildApprovalsRequestedMove(suite.DB(), nil, nil) serviceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ { diff --git a/pkg/services/mto_service_item.go b/pkg/services/mto_service_item.go index 25926ae3fca..914823809c3 100644 --- a/pkg/services/mto_service_item.go +++ b/pkg/services/mto_service_item.go @@ -32,6 +32,7 @@ type MTOServiceItemUpdater interface { ApproveOrRejectServiceItem(appCtx appcontext.AppContext, mtoServiceItemID uuid.UUID, status models.MTOServiceItemStatus, rejectionReason *string, eTag string) (*models.MTOServiceItem, error) UpdateMTOServiceItem(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, eTag string, validator string) (*models.MTOServiceItem, error) UpdateMTOServiceItemBasic(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, eTag string) (*models.MTOServiceItem, error) + UpdateMTOServiceItemPricingEstimate(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, shipment models.MTOShipment, eTag string) (*models.MTOServiceItem, error) UpdateMTOServiceItemPrime(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, planner route.Planner, shipment models.MTOShipment, eTag string) (*models.MTOServiceItem, error) ConvertItemToCustomerExpense(appCtx appcontext.AppContext, shipment *models.MTOShipment, customerExpenseReason *string, convertToCustomerExpense bool) (*models.MTOServiceItem, error) } diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index b2ac848273f..1bbbb60afac 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -3,6 +3,7 @@ package mtoserviceitem import ( "database/sql" "fmt" + "strconv" "time" "github.com/gobuffalo/validate/v3" @@ -19,6 +20,7 @@ import ( movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" "github.com/transcom/mymove/pkg/services/query" sitstatus "github.com/transcom/mymove/pkg/services/sit_status" + "github.com/transcom/mymove/pkg/unit" ) // OriginSITLocation is the constant representing when the shipment in storage occurs at the origin @@ -37,22 +39,28 @@ type mtoServiceItemQueryBuilder interface { } type mtoServiceItemUpdater struct { - planner route.Planner - builder mtoServiceItemQueryBuilder - createNewBuilder func() mtoServiceItemQueryBuilder - moveRouter services.MoveRouter - shipmentFetcher services.MTOShipmentFetcher - addressCreator services.AddressCreator + planner route.Planner + builder mtoServiceItemQueryBuilder + createNewBuilder func() mtoServiceItemQueryBuilder + moveRouter services.MoveRouter + shipmentFetcher services.MTOShipmentFetcher + addressCreator services.AddressCreator + unpackPricer services.DomesticUnpackPricer + linehaulPricer services.DomesticLinehaulPricer + destinationPricer services.DomesticDestinationPricer + fuelSurchargePricer services.FuelSurchargePricer + sitFuelSurchargePricer services.DomesticDestinationSITFuelSurchargePricer + sitDeliverPricer services.DomesticDestinationSITDeliveryPricer } // NewMTOServiceItemUpdater returns a new mto service item updater -func NewMTOServiceItemUpdater(planner route.Planner, builder mtoServiceItemQueryBuilder, moveRouter services.MoveRouter, shipmentFetcher services.MTOShipmentFetcher, addressCreator services.AddressCreator) services.MTOServiceItemUpdater { +func NewMTOServiceItemUpdater(planner route.Planner, builder mtoServiceItemQueryBuilder, moveRouter services.MoveRouter, shipmentFetcher services.MTOShipmentFetcher, addressCreator services.AddressCreator, unpackPricer services.DomesticUnpackPricer, linehaulPricer services.DomesticLinehaulPricer, destinationPricer services.DomesticDestinationPricer, fuelSurchargePricer services.FuelSurchargePricer, domesticDestinationSITDeliveryPricer services.DomesticDestinationSITDeliveryPricer, domesticDestinationSITFuelSurchargePricer services.DomesticDestinationSITFuelSurchargePricer) services.MTOServiceItemUpdater { // used inside a transaction and mocking return &mtoServiceItemUpdater{builder: builder} createNewBuilder := func() mtoServiceItemQueryBuilder { return query.NewQueryBuilder() } - return &mtoServiceItemUpdater{planner, builder, createNewBuilder, moveRouter, shipmentFetcher, addressCreator} + return &mtoServiceItemUpdater{planner, builder, createNewBuilder, moveRouter, shipmentFetcher, addressCreator, unpackPricer, linehaulPricer, destinationPricer, fuelSurchargePricer, domesticDestinationSITFuelSurchargePricer, domesticDestinationSITDeliveryPricer} } func (p *mtoServiceItemUpdater) ApproveOrRejectServiceItem( @@ -118,6 +126,121 @@ func (p *mtoServiceItemUpdater) ConvertItemToCustomerExpense( return p.convertItemToCustomerExpense(appCtx, *mtoServiceItem, customerExpenseReason, convertToCustomerExpense, eTag, checkETag()) } +func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, serviceItem *models.MTOServiceItem, mtoShipment models.MTOShipment) (unit.Cents, error) { + if serviceItem.ReService.Code == models.ReServiceCodeDDP || + serviceItem.ReService.Code == models.ReServiceCodeDUPK || + serviceItem.ReService.Code == models.ReServiceCodeDLH || + serviceItem.ReService.Code == models.ReServiceCodeFSC || + serviceItem.ReService.Code == models.ReServiceCodeDDDSIT || + serviceItem.ReService.Code == models.ReServiceCodeDDSFSC { + + isPPM := false + if mtoShipment.ShipmentType == models.MTOShipmentTypePPM { + isPPM = true + } + requestedPickupDate := *mtoShipment.RequestedPickupDate + currTime := time.Now() + var distance int + primeEstimatedWeight := *mtoShipment.PrimeEstimatedWeight + + contractCode, err := FetchContractCode(appCtx, currTime) + if err != nil { + contractCode, err = FetchContractCode(appCtx, requestedPickupDate) + if err != nil { + return 0, err + } + } + + var price unit.Cents + + // destination + if serviceItem.ReService.Code == models.ReServiceCodeDDP { + var domesticServiceArea models.ReDomesticServiceArea + if mtoShipment.DestinationAddress != nil { + domesticServiceArea, err = fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + + price, _, err = p.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + if err != nil { + return 0, err + } + } + if serviceItem.ReService.Code == models.ReServiceCodeDUPK { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + + serviceScheduleDestination := domesticServiceArea.ServicesSchedule + + price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, serviceScheduleDestination, isPPM) + if err != nil { + return 0, err + } + } + + // linehaul + if serviceItem.ReService.Code == models.ReServiceCodeDLH { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.PickupAddress.PostalCode) + if err != nil { + return 0, err + } + if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { + distance, err = p.planner.ZipTransitDistance(appCtx, mtoShipment.PickupAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + price, _, err = p.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + if err != nil { + return 0, err + } + } + // fuel surcharge + if serviceItem.ReService.Code == models.ReServiceCodeFSC { + var pickupDateForFSC time.Time + + // actual pickup date likely won't exist at the time of service item creation, but it could + // use requested pickup date if no actual date exists + if mtoShipment.ActualPickupDate != nil { + pickupDateForFSC = *mtoShipment.ActualPickupDate + } else { + pickupDateForFSC = requestedPickupDate + } + + if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { + distance, err = p.planner.ZipTransitDistance(appCtx, mtoShipment.PickupAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + + fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, primeEstimatedWeight) + if err != nil { + return 0, err + } + fscWeightBasedDistanceMultiplierFloat, err := strconv.ParseFloat(fscWeightBasedDistanceMultiplier, 64) + if err != nil { + return 0, err + } + eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, pickupDateForFSC) + if err != nil { + return 0, err + } + price, _, err = p.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), primeEstimatedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + if err != nil { + return 0, err + } + + } + return price, nil + } + return 0, nil +} + func (p *mtoServiceItemUpdater) findServiceItem(appCtx appcontext.AppContext, serviceItemID uuid.UUID) (*models.MTOServiceItem, error) { var serviceItem models.MTOServiceItem err := appCtx.DB().Q().EagerPreload( @@ -299,6 +422,21 @@ func (p *mtoServiceItemUpdater) convertItemToCustomerExpense( return &serviceItem, nil } +// UpdateMTOServiceItemPricingEstimate updates the MTO Service Item pricing estimate +func (p *mtoServiceItemUpdater) UpdateMTOServiceItemPricingEstimate( + appCtx appcontext.AppContext, + mtoServiceItem *models.MTOServiceItem, + shipment models.MTOShipment, + eTag string, +) (*models.MTOServiceItem, error) { + estimatedPrice, err := p.findEstimatedPrice(appCtx, mtoServiceItem, shipment) + if estimatedPrice != 0 && err != nil { + mtoServiceItem.PricingEstimate = &estimatedPrice + return p.UpdateMTOServiceItem(appCtx, mtoServiceItem, eTag, UpdateMTOServiceItemBasicValidator) + } + return mtoServiceItem, err +} + // UpdateMTOServiceItemBasic updates the MTO Service Item using base validators func (p *mtoServiceItemUpdater) UpdateMTOServiceItemBasic( appCtx appcontext.AppContext, diff --git a/pkg/services/mto_service_item/mto_service_item_updater_test.go b/pkg/services/mto_service_item/mto_service_item_updater_test.go index 47c55beda43..22259ed6aad 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater_test.go +++ b/pkg/services/mto_service_item/mto_service_item_updater_test.go @@ -23,6 +23,7 @@ import ( "github.com/transcom/mymove/pkg/models" mocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services/address" + "github.com/transcom/mymove/pkg/services/ghcrateengine" moverouter "github.com/transcom/mymove/pkg/services/move" movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" @@ -48,7 +49,7 @@ func (suite *MTOServiceItemServiceSuite) TestMTOServiceItemUpdater() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator) + updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) setupServiceItem := func() (models.MTOServiceItem, string) { serviceItem := testdatagen.MakeDefaultMTOServiceItem(suite.DB()) @@ -1757,7 +1758,7 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemStatus() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator) + updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) rejectionReason := models.StringPointer("") diff --git a/pkg/services/mto_service_item/mto_service_item_validators.go b/pkg/services/mto_service_item/mto_service_item_validators.go index 09d9c1b09ee..f3423517301 100644 --- a/pkg/services/mto_service_item/mto_service_item_validators.go +++ b/pkg/services/mto_service_item/mto_service_item_validators.go @@ -616,6 +616,9 @@ func (v *updateMTOServiceItemData) setNewMTOServiceItem() *models.MTOServiceItem newMTOServiceItem.ActualWeight = services.SetOptionalPoundField( v.updatedServiceItem.ActualWeight, newMTOServiceItem.ActualWeight) + newMTOServiceItem.PricingEstimate = services.SetNoNilOptionalCentField( + v.updatedServiceItem.PricingEstimate, newMTOServiceItem.PricingEstimate) + return &newMTOServiceItem } diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index 1b75b668336..18f0ffda5a4 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -465,7 +465,7 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc if tooApprovalStatus == models.ShipmentAddressUpdateStatusApproved { queryBuilder := query.NewQueryBuilder() - serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(f.planner, queryBuilder, f.moveRouter, f.shipmentFetcher, f.addressCreator) + serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(f.planner, queryBuilder, f.moveRouter, f.shipmentFetcher, f.addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(f.planner, queryBuilder, f.moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) addressUpdate.Status = models.ShipmentAddressUpdateStatusApproved @@ -497,6 +497,38 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc return nil, apperror.NewQueryError("MTOShipment", err, "") } + shipmentHasApprovedDestSIT := f.doesShipmentContainApprovedDestinationSIT(shipmentDetails) + + for i, serviceItem := range shipmentDetails.MTOServiceItems { + var updatedServiceItem *models.MTOServiceItem + if serviceItem.ReService.Code == models.ReServiceCodeDDP || serviceItem.ReService.Code == models.ReServiceCodeDUPK { + updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) + if err != nil { + return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) + } + } + + if !shipmentHasApprovedDestSIT { + if serviceItem.ReService.Code == models.ReServiceCodeDLH || serviceItem.ReService.Code == models.ReServiceCodeFSC { + updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) + if err != nil { + return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) + } + } + } else { + if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC || serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { + updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) + if err != nil { + return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) + } + } + } + + if updatedServiceItem != nil { + shipmentDetails.MTOServiceItems[i] = *updatedServiceItem + } + } + // If the pricing type has changed then we automatically reject the DLH or DSH service item on the shipment since it is now inaccurate var approvedPaymentRequestsExistsForServiceItem bool if haulPricingTypeHasChanged && len(shipment.MTOServiceItems) > 0 { @@ -512,8 +544,6 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc return nil, apperror.NewQueryError("ServiceItemPaymentRequests", err, "") } - shipmentHasApprovedDestSIT := f.doesShipmentContainApprovedDestinationSIT(shipmentDetails) - // do NOT regenerate any service items if the following conditions exist: // payment has already been approved for DLH or DSH service item // destination SIT is on shipment and any of the service items have an appproved status diff --git a/pkg/services/sit_extension/sit_extension_denier.go b/pkg/services/sit_extension/sit_extension_denier.go index 5d677c353b4..bc0ddf8c100 100644 --- a/pkg/services/sit_extension/sit_extension_denier.go +++ b/pkg/services/sit_extension/sit_extension_denier.go @@ -15,6 +15,7 @@ import ( routemocks "github.com/transcom/mymove/pkg/route/mocks" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/address" + "github.com/transcom/mymove/pkg/services/ghcrateengine" mtoserviceitem "github.com/transcom/mymove/pkg/services/mto_service_item" mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment" "github.com/transcom/mymove/pkg/services/query" @@ -33,7 +34,7 @@ func NewSITExtensionDenier(moveRouter services.MoveRouter) services.SITExtension mock.Anything, mock.Anything, ).Return(400, nil) - return &sitExtensionDenier{moveRouter, mtoserviceitem.NewMTOServiceItemUpdater(planner, query.NewQueryBuilder(), moveRouter, mtoshipment.NewMTOShipmentFetcher(), address.NewAddressCreator())} + return &sitExtensionDenier{moveRouter, mtoserviceitem.NewMTOServiceItemUpdater(planner, query.NewQueryBuilder(), moveRouter, mtoshipment.NewMTOShipmentFetcher(), address.NewAddressCreator(), ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer())} } // DenySITExtension denies the SIT Extension diff --git a/pkg/testdatagen/scenario/shared.go b/pkg/testdatagen/scenario/shared.go index 44f2bce1b66..e39b3b3a564 100644 --- a/pkg/testdatagen/scenario/shared.go +++ b/pkg/testdatagen/scenario/shared.go @@ -4274,7 +4274,7 @@ func createHHGWithOriginSITServiceItems( mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator) + serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) var originFirstDaySIT models.MTOServiceItem var originAdditionalDaySIT models.MTOServiceItem @@ -4535,7 +4535,7 @@ func createHHGWithDestinationSITServiceItems(appCtx appcontext.AppContext, prime mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator) + serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) var destinationFirstDaySIT models.MTOServiceItem var destinationAdditionalDaySIT models.MTOServiceItem @@ -5014,7 +5014,7 @@ func createHHGWithPaymentServiceItems( mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator) + serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) var originFirstDaySIT models.MTOServiceItem var originAdditionalDaySIT models.MTOServiceItem From a84a0b16e65f2514f8489b140256528511ebc2f5 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Wed, 13 Nov 2024 11:16:59 -0600 Subject: [PATCH 02/19] Adding in addtional service items to be repriced --- .../mto_service_item_updater.go | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 1bbbb60afac..880c235bddf 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -199,6 +199,72 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } + // unpacking + if serviceItem.ReService.Code == models.ReServiceCodeDUPK { + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServicesSchedule, isPPM) + if err != nil { + return 0, err + } + } + // destination sit delivery + if serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { + var pickupDate time.Time + if mtoShipment.ActualPickupDate != nil { + pickupDate = *mtoShipment.ActualPickupDate + } else { + pickupDate = requestedPickupDate + } + domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + if mtoShipment.DestinationAddress != nil { + distance, err = p.planner.ZipTransitDistance(appCtx, serviceItem.SITDestinationFinalAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + price, _, err = p.sitDeliverPricer.Price(appCtx, contractCode, pickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, domesticServiceArea.SITPDSchedule, mtoShipment.DestinationAddress.PostalCode, serviceItem.SITDestinationFinalAddress.PostalCode, unit.Miles(distance)) + if err != nil { + return 0, err + } + } + // destination sit fuel surcharge + if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC { + var pickupDateForFSC time.Time + if mtoShipment.ActualPickupDate != nil { + pickupDateForFSC = *mtoShipment.ActualPickupDate + } else { + pickupDateForFSC = requestedPickupDate + } + + if mtoShipment.DestinationAddress != nil { + distance, err = p.planner.ZipTransitDistance(appCtx, serviceItem.SITDestinationFinalAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) + if err != nil { + return 0, err + } + } + fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, primeEstimatedWeight) + if err != nil { + return 0, err + } + fscWeightBasedDistanceMultiplierFloat, err := strconv.ParseFloat(fscWeightBasedDistanceMultiplier, 64) + if err != nil { + return 0, err + } + eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, pickupDateForFSC) + if err != nil { + return 0, err + } + price, _, err = p.sitFuelSurchargePricer.Price(appCtx, *mtoShipment.ActualPickupDate, unit.Miles(distance), *mtoShipment.PrimeEstimatedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + if err != nil { + return 0, err + } + } // fuel surcharge if serviceItem.ReService.Code == models.ReServiceCodeFSC { var pickupDateForFSC time.Time From 5afa0f2380abb24d36d8e8acbf6c848e347a4f99 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Wed, 13 Nov 2024 13:16:33 -0600 Subject: [PATCH 03/19] Handling weight changes --- .../mto_service_item_updater.go | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 880c235bddf..35b549159b2 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -141,7 +141,17 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, requestedPickupDate := *mtoShipment.RequestedPickupDate currTime := time.Now() var distance int - primeEstimatedWeight := *mtoShipment.PrimeEstimatedWeight + + var shipmentWeight unit.Pound + if mtoShipment.PrimeActualWeight != nil { + shipmentWeight = *mtoShipment.PrimeActualWeight + } else { + if mtoShipment.PrimeEstimatedWeight != nil { + shipmentWeight = *mtoShipment.PrimeEstimatedWeight + } else { + shipmentWeight = 0 + } + } contractCode, err := FetchContractCode(appCtx, currTime) if err != nil { @@ -163,7 +173,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } } - price, _, err = p.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + price, _, err = p.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, shipmentWeight, domesticServiceArea.ServiceArea, isPPM) if err != nil { return 0, err } @@ -176,7 +186,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, serviceScheduleDestination := domesticServiceArea.ServicesSchedule - price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, serviceScheduleDestination, isPPM) + price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, shipmentWeight, serviceScheduleDestination, isPPM) if err != nil { return 0, err } @@ -194,7 +204,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - price, _, err = p.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, isPPM) + price, _, err = p.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), shipmentWeight, domesticServiceArea.ServiceArea, isPPM) if err != nil { return 0, err } @@ -205,7 +215,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServicesSchedule, isPPM) + price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, shipmentWeight, domesticServiceArea.ServicesSchedule, isPPM) if err != nil { return 0, err } @@ -228,7 +238,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - price, _, err = p.sitDeliverPricer.Price(appCtx, contractCode, pickupDate, *mtoShipment.PrimeEstimatedWeight, domesticServiceArea.ServiceArea, domesticServiceArea.SITPDSchedule, mtoShipment.DestinationAddress.PostalCode, serviceItem.SITDestinationFinalAddress.PostalCode, unit.Miles(distance)) + price, _, err = p.sitDeliverPricer.Price(appCtx, contractCode, pickupDate, shipmentWeight, domesticServiceArea.ServiceArea, domesticServiceArea.SITPDSchedule, mtoShipment.DestinationAddress.PostalCode, serviceItem.SITDestinationFinalAddress.PostalCode, unit.Miles(distance)) if err != nil { return 0, err } @@ -248,7 +258,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, primeEstimatedWeight) + fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, shipmentWeight) if err != nil { return 0, err } @@ -260,7 +270,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - price, _, err = p.sitFuelSurchargePricer.Price(appCtx, *mtoShipment.ActualPickupDate, unit.Miles(distance), *mtoShipment.PrimeEstimatedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + price, _, err = p.sitFuelSurchargePricer.Price(appCtx, *mtoShipment.ActualPickupDate, unit.Miles(distance), shipmentWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) if err != nil { return 0, err } @@ -284,7 +294,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } } - fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, primeEstimatedWeight) + fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, shipmentWeight) if err != nil { return 0, err } @@ -296,7 +306,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - price, _, err = p.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), primeEstimatedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + price, _, err = p.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), shipmentWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) if err != nil { return 0, err } From 0439356be42855148c2641fa1fd574dfe2e4d657 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Thu, 14 Nov 2024 04:37:37 +0000 Subject: [PATCH 04/19] updating shipment address update tests --- .../shipment_address_update_requester_test.go | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester_test.go b/pkg/services/shipment_address_update/shipment_address_update_requester_test.go index 863e1851d21..2e67fd6ce34 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester_test.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester_test.go @@ -14,8 +14,34 @@ import ( "github.com/transcom/mymove/pkg/services/address" moveservices "github.com/transcom/mymove/pkg/services/move" "github.com/transcom/mymove/pkg/testdatagen" + "github.com/transcom/mymove/pkg/unit" ) +func (suite *ShipmentAddressUpdateServiceSuite) setupServiceItemData() { + originalDomesticServiceArea := testdatagen.FetchOrMakeReDomesticServiceArea(suite.AppContextForTest().DB(), testdatagen.Assertions{ + ReDomesticServiceArea: models.ReDomesticServiceArea{ + ServiceArea: "004", + ServicesSchedule: 2, + }, + ReContract: testdatagen.FetchOrMakeReContract(suite.AppContextForTest().DB(), testdatagen.Assertions{}), + }) + + testdatagen.FetchOrMakeReDomesticLinehaulPrice(suite.DB(), testdatagen.Assertions{ + ReDomesticLinehaulPrice: models.ReDomesticLinehaulPrice{ + Contract: originalDomesticServiceArea.Contract, + ContractID: originalDomesticServiceArea.ContractID, + DomesticServiceArea: originalDomesticServiceArea, + DomesticServiceAreaID: originalDomesticServiceArea.ID, + WeightLower: unit.Pound(500), + WeightUpper: unit.Pound(9999), + MilesLower: 500, + MilesUpper: 9999, + PriceMillicents: unit.Millicents(606800), + IsPeakPeriod: false, + }, + }) +} + func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddressUpdate() { setupTestData := func() models.Move { testdatagen.FetchOrMakeReContractYear(suite.DB(), testdatagen.Assertions{ @@ -587,6 +613,8 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp suite.Run("TOO approves address change", func() { + suite.setupServiceItemData() + addressChange := factory.BuildShipmentAddressUpdate(suite.DB(), nil, []factory.Trait{ factory.GetTraitAvailableToPrimeMove, }) @@ -849,6 +877,9 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp "90210", ).Return(2500, nil).Once() move := setupTestData() + + suite.setupServiceItemData() + shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), []factory.Customization{ { Model: models.Address{ @@ -915,6 +946,9 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp "90210", ).Return(2500, nil).Once() move := setupTestData() + + suite.setupServiceItemData() + shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), []factory.Customization{ { Model: models.Address{ @@ -970,6 +1004,9 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp suite.Run("Service items are not rejected when pricing type does not change post TOO approval", func() { move := setupTestData() + + suite.setupServiceItemData() + shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), nil, nil) //Generate service items to test their statuses upon approval @@ -1014,6 +1051,9 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp "90210", ).Return(2500, nil).Once() move := setupTestData() + + suite.setupServiceItemData() + shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), []factory.Customization{ { Model: models.Address{ @@ -1081,6 +1121,9 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp PostalCode: "90210", } move := setupTestData() + + suite.setupServiceItemData() + shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), []factory.Customization{ { Model: models.Address{ From 12eb8377a54f5b73f4cd2f055c66873dd7886ffd Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Thu, 14 Nov 2024 14:29:22 +0000 Subject: [PATCH 05/19] Adding ReContractYear data generation to shipment address tests --- .../shipment_address_update_requester_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester_test.go b/pkg/services/shipment_address_update/shipment_address_update_requester_test.go index 2e67fd6ce34..034b1420152 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester_test.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester_test.go @@ -40,6 +40,17 @@ func (suite *ShipmentAddressUpdateServiceSuite) setupServiceItemData() { IsPeakPeriod: false, }, }) + + testdatagen.FetchOrMakeReContractYear(suite.DB(), testdatagen.Assertions{ + ReContractYear: models.ReContractYear{ + Contract: originalDomesticServiceArea.Contract, + ContractID: originalDomesticServiceArea.ContractID, + StartDate: time.Date(2019, time.June, 1, 0, 0, 0, 0, time.UTC), + EndDate: time.Date(2030, time.May, 31, 0, 0, 0, 0, time.UTC), + Escalation: 1.0, + EscalationCompounded: 1.0, + }, + }) } func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddressUpdate() { From 484018aa6af4878ff9a51ce1e7aad0fabb639684 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Thu, 14 Nov 2024 15:24:31 +0000 Subject: [PATCH 06/19] Updating shipment address request tests --- .../shipment_address_update_requester_test.go | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester_test.go b/pkg/services/shipment_address_update/shipment_address_update_requester_test.go index 034b1420152..b2edfc521dd 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester_test.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester_test.go @@ -18,6 +18,16 @@ import ( ) func (suite *ShipmentAddressUpdateServiceSuite) setupServiceItemData() { + startDate := time.Date(2020, time.January, 1, 12, 0, 0, 0, time.UTC) + endDate := time.Date(2020, time.December, 31, 12, 0, 0, 0, time.UTC) + + testdatagen.FetchOrMakeReContractYear(suite.DB(), testdatagen.Assertions{ + ReContractYear: models.ReContractYear{ + StartDate: startDate, + EndDate: endDate, + }, + }) + originalDomesticServiceArea := testdatagen.FetchOrMakeReDomesticServiceArea(suite.AppContextForTest().DB(), testdatagen.Assertions{ ReDomesticServiceArea: models.ReDomesticServiceArea{ ServiceArea: "004", @@ -40,17 +50,6 @@ func (suite *ShipmentAddressUpdateServiceSuite) setupServiceItemData() { IsPeakPeriod: false, }, }) - - testdatagen.FetchOrMakeReContractYear(suite.DB(), testdatagen.Assertions{ - ReContractYear: models.ReContractYear{ - Contract: originalDomesticServiceArea.Contract, - ContractID: originalDomesticServiceArea.ContractID, - StartDate: time.Date(2019, time.June, 1, 0, 0, 0, 0, time.UTC), - EndDate: time.Date(2030, time.May, 31, 0, 0, 0, 0, time.UTC), - Escalation: 1.0, - EscalationCompounded: 1.0, - }, - }) } func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddressUpdate() { @@ -1030,6 +1029,11 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp State: "CA", PostalCode: shipment.DestinationAddress.PostalCode, } + mockPlanner.On("ZipTransitDistance", + mock.AnythingOfType("*appcontext.appContext"), + "90210", + "94535", + ).Return(2500, nil).Once() mockPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), "94535", From d14adc4c4a5bb84405040e4c968ea5dc9028d953 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Thu, 14 Nov 2024 18:31:30 +0000 Subject: [PATCH 07/19] Adding tests for UpdateMTOSeriveItemPricingEstimate --- .../mto_service_item_updater_test.go | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/pkg/services/mto_service_item/mto_service_item_updater_test.go b/pkg/services/mto_service_item/mto_service_item_updater_test.go index 11fdf619b79..39d40caead6 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater_test.go +++ b/pkg/services/mto_service_item/mto_service_item_updater_test.go @@ -2346,6 +2346,110 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemStatus() { }) } +func (suite *MTOServiceItemServiceSuite) setupServiceItemData() { + startDate := time.Date(2020, time.January, 1, 12, 0, 0, 0, time.UTC) + endDate := time.Date(2020, time.December, 31, 12, 0, 0, 0, time.UTC) + + testdatagen.FetchOrMakeReContractYear(suite.DB(), testdatagen.Assertions{ + ReContractYear: models.ReContractYear{ + StartDate: startDate, + EndDate: endDate, + }, + }) + + originalDomesticServiceArea := testdatagen.FetchOrMakeReDomesticServiceArea(suite.AppContextForTest().DB(), testdatagen.Assertions{ + ReDomesticServiceArea: models.ReDomesticServiceArea{ + ServiceArea: "004", + ServicesSchedule: 2, + }, + ReContract: testdatagen.FetchOrMakeReContract(suite.AppContextForTest().DB(), testdatagen.Assertions{}), + }) + + testdatagen.FetchOrMakeReDomesticLinehaulPrice(suite.DB(), testdatagen.Assertions{ + ReDomesticLinehaulPrice: models.ReDomesticLinehaulPrice{ + Contract: originalDomesticServiceArea.Contract, + ContractID: originalDomesticServiceArea.ContractID, + DomesticServiceArea: originalDomesticServiceArea, + DomesticServiceAreaID: originalDomesticServiceArea.ID, + WeightLower: unit.Pound(500), + WeightUpper: unit.Pound(9999), + MilesLower: 500, + MilesUpper: 9999, + PriceMillicents: unit.Millicents(606800), + IsPeakPeriod: false, + }, + }) +} + +func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate() { + suite.setupServiceItemData() + builder := query.NewQueryBuilder() + moveRouter := moverouter.NewMoveRouter() + shipmentFetcher := mtoshipment.NewMTOShipmentFetcher() + addressCreator := address.NewAddressCreator() + planner := &mocks.Planner{} + planner.On("ZipTransitDistance", + mock.AnythingOfType("*appcontext.appContext"), + mock.Anything, + mock.Anything, + ).Return(400, nil) + updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + + setupServiceItem := func() (models.MTOServiceItem, string) { + serviceItem := testdatagen.MakeDefaultMTOServiceItem(suite.DB()) + eTag := etag.GenerateEtag(serviceItem.UpdatedAt) + return serviceItem, eTag + } + + now := time.Now() + year, month, day := now.Add(time.Hour * 24 * -30).Date() + aMonthAgo := time.Date(year, month, day, 0, 0, 0, 0, time.UTC) + move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil) + shipmentSITAllowance := int(90) + estimatedWeight := unit.Pound(1400) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + SITDaysAllowance: &shipmentSITAllowance, + PrimeEstimatedWeight: &estimatedWeight, + RequiredDeliveryDate: &aMonthAgo, + UpdatedAt: aMonthAgo, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + suite.Run("Validation Error", func() { + serviceItem, eTag := setupServiceItem() + invalidServiceItem := serviceItem + invalidServiceItem.MoveTaskOrderID = serviceItem.ID // invalid Move ID + + updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &invalidServiceItem, shipment, eTag) + + suite.Nil(updatedServiceItem) + suite.Error(err) + suite.IsType(apperror.InvalidInputError{}, err) + + invalidInputError := err.(apperror.InvalidInputError) + suite.True(invalidInputError.ValidationErrors.HasAny()) + suite.Contains(invalidInputError.ValidationErrors.Keys(), "moveTaskOrderID") + }) + + suite.Run("Returns updated service item on success", func() { + serviceItem, eTag := setupServiceItem() + + updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &serviceItem, shipment, eTag) + + suite.NotNil(updatedServiceItem) + suite.Nil(err) + }) +} + // Helper function to create a rejected service item func buildRejectedServiceItem(suite *MTOServiceItemServiceSuite, reServiceCode models.ReServiceCode, reason string, contactDatePlusGracePeriod, aMonthAgo, now, sitRequestedDelivery time.Time, requestApprovalsRequestedStatus bool) models.MTOServiceItem { return factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ From daa6151c9d413129bbdacd8d997a2672e110a58d Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Fri, 15 Nov 2024 12:17:44 +0000 Subject: [PATCH 08/19] Updating service item updater tests --- .../mto_service_item_updater.go | 2 +- .../mto_service_item_updater_test.go | 45 +++++++------------ 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 35b549159b2..3d1b16b6ec5 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -506,7 +506,7 @@ func (p *mtoServiceItemUpdater) UpdateMTOServiceItemPricingEstimate( eTag string, ) (*models.MTOServiceItem, error) { estimatedPrice, err := p.findEstimatedPrice(appCtx, mtoServiceItem, shipment) - if estimatedPrice != 0 && err != nil { + if estimatedPrice != 0 && err == nil { mtoServiceItem.PricingEstimate = &estimatedPrice return p.UpdateMTOServiceItem(appCtx, mtoServiceItem, eTag, UpdateMTOServiceItemBasicValidator) } diff --git a/pkg/services/mto_service_item/mto_service_item_updater_test.go b/pkg/services/mto_service_item/mto_service_item_updater_test.go index 39d40caead6..aaf18b3beef 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater_test.go +++ b/pkg/services/mto_service_item/mto_service_item_updater_test.go @@ -2357,12 +2357,21 @@ func (suite *MTOServiceItemServiceSuite) setupServiceItemData() { }, }) - originalDomesticServiceArea := testdatagen.FetchOrMakeReDomesticServiceArea(suite.AppContextForTest().DB(), testdatagen.Assertions{ + originalDomesticServiceArea := testdatagen.FetchOrMakeReDomesticServiceArea(suite.DB(), testdatagen.Assertions{ ReDomesticServiceArea: models.ReDomesticServiceArea{ ServiceArea: "004", ServicesSchedule: 2, }, - ReContract: testdatagen.FetchOrMakeReContract(suite.AppContextForTest().DB(), testdatagen.Assertions{}), + ReContract: testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{}), + }) + + testdatagen.FetchOrMakeReZip3(suite.DB(), testdatagen.Assertions{ + ReZip3: models.ReZip3{ + Contract: originalDomesticServiceArea.Contract, + ContractID: originalDomesticServiceArea.ContractID, + DomesticServiceArea: originalDomesticServiceArea, + Zip3: "902", + }, }) testdatagen.FetchOrMakeReDomesticLinehaulPrice(suite.DB(), testdatagen.Assertions{ @@ -2373,7 +2382,7 @@ func (suite *MTOServiceItemServiceSuite) setupServiceItemData() { DomesticServiceAreaID: originalDomesticServiceArea.ID, WeightLower: unit.Pound(500), WeightUpper: unit.Pound(9999), - MilesLower: 500, + MilesLower: 250, MilesUpper: 9999, PriceMillicents: unit.Millicents(606800), IsPeakPeriod: false, @@ -2382,7 +2391,6 @@ func (suite *MTOServiceItemServiceSuite) setupServiceItemData() { } func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate() { - suite.setupServiceItemData() builder := query.NewQueryBuilder() moveRouter := moverouter.NewMoveRouter() shipmentFetcher := mtoshipment.NewMTOShipmentFetcher() @@ -2401,35 +2409,13 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate return serviceItem, eTag } - now := time.Now() - year, month, day := now.Add(time.Hour * 24 * -30).Date() - aMonthAgo := time.Date(year, month, day, 0, 0, 0, 0, time.UTC) - move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil) - shipmentSITAllowance := int(90) - estimatedWeight := unit.Pound(1400) - - shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ - { - Model: models.MTOShipment{ - Status: models.MTOShipmentStatusApproved, - SITDaysAllowance: &shipmentSITAllowance, - PrimeEstimatedWeight: &estimatedWeight, - RequiredDeliveryDate: &aMonthAgo, - UpdatedAt: aMonthAgo, - }, - }, - { - Model: move, - LinkOnly: true, - }, - }, nil) - suite.Run("Validation Error", func() { + suite.setupServiceItemData() serviceItem, eTag := setupServiceItem() invalidServiceItem := serviceItem invalidServiceItem.MoveTaskOrderID = serviceItem.ID // invalid Move ID - updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &invalidServiceItem, shipment, eTag) + updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &invalidServiceItem, serviceItem.MTOShipment, eTag) suite.Nil(updatedServiceItem) suite.Error(err) @@ -2441,9 +2427,10 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate }) suite.Run("Returns updated service item on success", func() { + suite.setupServiceItemData() serviceItem, eTag := setupServiceItem() - updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &serviceItem, shipment, eTag) + updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &serviceItem, serviceItem.MTOShipment, eTag) suite.NotNil(updatedServiceItem) suite.Nil(err) From 5216f158e4243791843cadeefa22ab8ae6ff2f8d Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Fri, 15 Nov 2024 14:23:44 +0000 Subject: [PATCH 09/19] Updating mto_service_item_updater tests --- .../mto_service_item_updater.go | 2 +- .../mto_service_item_updater_test.go | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 3d1b16b6ec5..13ff315337b 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -149,7 +149,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if mtoShipment.PrimeEstimatedWeight != nil { shipmentWeight = *mtoShipment.PrimeEstimatedWeight } else { - shipmentWeight = 0 + return 0, apperror.NewInvalidInputError(serviceItem.ID, nil, nil, "No estimated or actual weight exists for this service item.") } } diff --git a/pkg/services/mto_service_item/mto_service_item_updater_test.go b/pkg/services/mto_service_item/mto_service_item_updater_test.go index aaf18b3beef..1baffb834e4 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater_test.go +++ b/pkg/services/mto_service_item/mto_service_item_updater_test.go @@ -2409,6 +2409,11 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate return serviceItem, eTag } + setupServiceItems := func() models.MTOServiceItems { + serviceItems := testdatagen.MakeMTOServiceItems(suite.DB()) + return serviceItems + } + suite.Run("Validation Error", func() { suite.setupServiceItemData() serviceItem, eTag := setupServiceItem() @@ -2426,14 +2431,17 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate suite.Contains(invalidInputError.ValidationErrors.Keys(), "moveTaskOrderID") }) - suite.Run("Returns updated service item on success", func() { + suite.Run("Returns updated service item on success wihtout error", func() { suite.setupServiceItemData() - serviceItem, eTag := setupServiceItem() + serviceItems := setupServiceItems() - updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &serviceItem, serviceItem.MTOShipment, eTag) + for _, serviceItem := range serviceItems { + eTag := etag.GenerateEtag(serviceItem.UpdatedAt) + updatedServiceItem, err := updater.UpdateMTOServiceItemPricingEstimate(suite.AppContextForTest(), &serviceItem, serviceItem.MTOShipment, eTag) - suite.NotNil(updatedServiceItem) - suite.Nil(err) + suite.NotNil(updatedServiceItem) + suite.Nil(err) + } }) } From e64002145fed84b053e009fbbbff275e5b9ee8aa Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Fri, 15 Nov 2024 15:28:44 +0000 Subject: [PATCH 10/19] Updating pickupdate for estimated incentive calculations --- .../mto_service_item_updater.go | 54 +++++++------------ 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 13ff315337b..6491b32e757 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -138,7 +138,16 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if mtoShipment.ShipmentType == models.MTOShipmentTypePPM { isPPM = true } - requestedPickupDate := *mtoShipment.RequestedPickupDate + + var pickupDate *time.Time + if mtoShipment.ActualPickupDate != nil { + pickupDate = mtoShipment.ActualPickupDate + } else { + if mtoShipment.RequestedPickupDate != nil { + pickupDate = mtoShipment.RequestedPickupDate + } + } + currTime := time.Now() var distance int @@ -154,8 +163,8 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } contractCode, err := FetchContractCode(appCtx, currTime) - if err != nil { - contractCode, err = FetchContractCode(appCtx, requestedPickupDate) + if err != nil && pickupDate != nil { + contractCode, err = FetchContractCode(appCtx, *pickupDate) if err != nil { return 0, err } @@ -173,7 +182,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } } - price, _, err = p.destinationPricer.Price(appCtx, contractCode, requestedPickupDate, shipmentWeight, domesticServiceArea.ServiceArea, isPPM) + price, _, err = p.destinationPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, domesticServiceArea.ServiceArea, isPPM) if err != nil { return 0, err } @@ -186,7 +195,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, serviceScheduleDestination := domesticServiceArea.ServicesSchedule - price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, shipmentWeight, serviceScheduleDestination, isPPM) + price, _, err = p.unpackPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, serviceScheduleDestination, isPPM) if err != nil { return 0, err } @@ -204,7 +213,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - price, _, err = p.linehaulPricer.Price(appCtx, contractCode, requestedPickupDate, unit.Miles(distance), shipmentWeight, domesticServiceArea.ServiceArea, isPPM) + price, _, err = p.linehaulPricer.Price(appCtx, contractCode, *pickupDate, unit.Miles(distance), shipmentWeight, domesticServiceArea.ServiceArea, isPPM) if err != nil { return 0, err } @@ -215,19 +224,13 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - price, _, err = p.unpackPricer.Price(appCtx, contractCode, requestedPickupDate, shipmentWeight, domesticServiceArea.ServicesSchedule, isPPM) + price, _, err = p.unpackPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, domesticServiceArea.ServicesSchedule, isPPM) if err != nil { return 0, err } } // destination sit delivery if serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { - var pickupDate time.Time - if mtoShipment.ActualPickupDate != nil { - pickupDate = *mtoShipment.ActualPickupDate - } else { - pickupDate = requestedPickupDate - } domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) if err != nil { return 0, err @@ -238,20 +241,13 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - price, _, err = p.sitDeliverPricer.Price(appCtx, contractCode, pickupDate, shipmentWeight, domesticServiceArea.ServiceArea, domesticServiceArea.SITPDSchedule, mtoShipment.DestinationAddress.PostalCode, serviceItem.SITDestinationFinalAddress.PostalCode, unit.Miles(distance)) + price, _, err = p.sitDeliverPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, domesticServiceArea.ServiceArea, domesticServiceArea.SITPDSchedule, mtoShipment.DestinationAddress.PostalCode, serviceItem.SITDestinationFinalAddress.PostalCode, unit.Miles(distance)) if err != nil { return 0, err } } // destination sit fuel surcharge if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC { - var pickupDateForFSC time.Time - if mtoShipment.ActualPickupDate != nil { - pickupDateForFSC = *mtoShipment.ActualPickupDate - } else { - pickupDateForFSC = requestedPickupDate - } - if mtoShipment.DestinationAddress != nil { distance, err = p.planner.ZipTransitDistance(appCtx, serviceItem.SITDestinationFinalAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) if err != nil { @@ -266,7 +262,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, pickupDateForFSC) + eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, *pickupDate) if err != nil { return 0, err } @@ -277,16 +273,6 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } // fuel surcharge if serviceItem.ReService.Code == models.ReServiceCodeFSC { - var pickupDateForFSC time.Time - - // actual pickup date likely won't exist at the time of service item creation, but it could - // use requested pickup date if no actual date exists - if mtoShipment.ActualPickupDate != nil { - pickupDateForFSC = *mtoShipment.ActualPickupDate - } else { - pickupDateForFSC = requestedPickupDate - } - if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { distance, err = p.planner.ZipTransitDistance(appCtx, mtoShipment.PickupAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) if err != nil { @@ -302,11 +288,11 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, pickupDateForFSC) + eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, *pickupDate) if err != nil { return 0, err } - price, _, err = p.fuelSurchargePricer.Price(appCtx, pickupDateForFSC, unit.Miles(distance), shipmentWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + price, _, err = p.fuelSurchargePricer.Price(appCtx, *pickupDate, unit.Miles(distance), shipmentWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) if err != nil { return 0, err } From 5647df2e6bafd7ff817c5dcd9cf61225e5ce4f88 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Tue, 26 Nov 2024 18:41:46 +0000 Subject: [PATCH 11/19] Adding nil check for prime weights --- .../shipment_address_update_requester.go | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index 18f0ffda5a4..10477183eb0 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -500,32 +500,34 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc shipmentHasApprovedDestSIT := f.doesShipmentContainApprovedDestinationSIT(shipmentDetails) for i, serviceItem := range shipmentDetails.MTOServiceItems { - var updatedServiceItem *models.MTOServiceItem - if serviceItem.ReService.Code == models.ReServiceCodeDDP || serviceItem.ReService.Code == models.ReServiceCodeDUPK { - updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) - if err != nil { - return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) - } - } - - if !shipmentHasApprovedDestSIT { - if serviceItem.ReService.Code == models.ReServiceCodeDLH || serviceItem.ReService.Code == models.ReServiceCodeFSC { + if serviceItem.MTOShipment.PrimeEstimatedWeight != nil || serviceItem.MTOShipment.PrimeActualWeight != nil { + var updatedServiceItem *models.MTOServiceItem + if serviceItem.ReService.Code == models.ReServiceCodeDDP || serviceItem.ReService.Code == models.ReServiceCodeDUPK { updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) if err != nil { return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) } } - } else { - if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC || serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { - updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) - if err != nil { - return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) + + if !shipmentHasApprovedDestSIT { + if serviceItem.ReService.Code == models.ReServiceCodeDLH || serviceItem.ReService.Code == models.ReServiceCodeFSC { + updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) + if err != nil { + return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) + } + } + } else { + if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC || serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { + updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) + if err != nil { + return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) + } } } - } - if updatedServiceItem != nil { - shipmentDetails.MTOServiceItems[i] = *updatedServiceItem + if updatedServiceItem != nil { + shipmentDetails.MTOServiceItems[i] = *updatedServiceItem + } } } From b3b2842423a440280594be1bb5223a093d3c7cff Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Tue, 3 Dec 2024 04:53:30 +0000 Subject: [PATCH 12/19] using shipment instead of serviceItem.Shipment --- .../shipment_address_update_requester.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index 10477183eb0..b67239a40ab 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -500,7 +500,7 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc shipmentHasApprovedDestSIT := f.doesShipmentContainApprovedDestinationSIT(shipmentDetails) for i, serviceItem := range shipmentDetails.MTOServiceItems { - if serviceItem.MTOShipment.PrimeEstimatedWeight != nil || serviceItem.MTOShipment.PrimeActualWeight != nil { + if shipment.PrimeEstimatedWeight != nil || shipment.PrimeActualWeight != nil { var updatedServiceItem *models.MTOServiceItem if serviceItem.ReService.Code == models.ReServiceCodeDDP || serviceItem.ReService.Code == models.ReServiceCodeDUPK { updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) From 657724ee620642a1a2b233df98ffdc089da8122d Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Wed, 4 Dec 2024 20:03:50 +0000 Subject: [PATCH 13/19] Updating MTOShipments query --- pkg/models/mto_service_items.go | 2 ++ pkg/services/mto_service_item/mto_service_item_updater.go | 4 ++-- .../shipment_address_update_requester.go | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/models/mto_service_items.go b/pkg/models/mto_service_items.go index 862a25fce32..d5cb39daeb3 100644 --- a/pkg/models/mto_service_items.go +++ b/pkg/models/mto_service_items.go @@ -89,7 +89,9 @@ type MTOServiceItemSingle struct { SITEntryDate *time.Time `db:"sit_entry_date"` SITDepartureDate *time.Time `db:"sit_departure_date"` SITDestinationFinalAddressID *uuid.UUID `db:"sit_destination_final_address_id"` + SITDestinationFinalAddress *Address `belongs_to:"addresses" fk_id:"sit_destination_final_address_id"` SITOriginHHGOriginalAddressID *uuid.UUID `db:"sit_origin_hhg_original_address_id"` + SITDestinationOriginalAddress *Address `belongs_to:"addresses" fk_id:"sit_destination_original_address_id"` SITOriginHHGActualAddressID *uuid.UUID `db:"sit_origin_hhg_actual_address_id"` EstimatedWeight *unit.Pound `db:"estimated_weight"` ActualWeight *unit.Pound `db:"actual_weight"` diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 6491b32e757..037c53c1da3 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -230,7 +230,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } } // destination sit delivery - if serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { + if serviceItem.ReService.Code == models.ReServiceCodeDDDSIT && serviceItem.SITDestinationFinalAddress != nil { domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) if err != nil { return 0, err @@ -247,7 +247,7 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } } // destination sit fuel surcharge - if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC { + if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC && serviceItem.SITDestinationFinalAddress != nil { if mtoShipment.DestinationAddress != nil { distance, err = p.planner.ZipTransitDistance(appCtx, serviceItem.SITDestinationFinalAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) if err != nil { diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index b67239a40ab..ae2ef7ceb03 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -489,7 +489,7 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc } var shipmentDetails models.MTOShipment - err = appCtx.DB().EagerPreload("MoveTaskOrder", "MTOServiceItems.ReService").Find(&shipmentDetails, shipmentID) + err = appCtx.DB().EagerPreload("MoveTaskOrder", "MTOServiceItems.ReService", "MTOServiceItems.SITDestinationOriginalAddress", "MTOServiceItems.SITDestinationFinalAddress").Find(&shipmentDetails, shipmentID) if err != nil { if err == sql.ErrNoRows { return nil, apperror.NewNotFoundError(shipmentID, "looking for shipment") From a912f6e0fb15e6bacf34381681af3871d1caad26 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Thu, 5 Dec 2024 15:30:54 +0000 Subject: [PATCH 14/19] Adding test to increase server_coverage after merge --- pkg/iws/rbs_error_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 pkg/iws/rbs_error_test.go diff --git a/pkg/iws/rbs_error_test.go b/pkg/iws/rbs_error_test.go new file mode 100644 index 00000000000..022ab8400b7 --- /dev/null +++ b/pkg/iws/rbs_error_test.go @@ -0,0 +1,15 @@ +package iws + +func (suite *iwsSuite) TestRbsError() { + data := ` + + 14030 + Problem with this argument: EMA_TX + ` + _, _, _, err := parseWkEmaResponse([]byte(data)) + suite.NotNil(err) + rbsError, ok := err.(*RbsError) + suite.True(ok) + suite.Equal(uint64(14030), rbsError.FaultCode) + suite.NotEmpty(rbsError.FaultMessage) +} From 74b5e7d0177f80e5708c03063b75021aa7f5cb1e Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Tue, 10 Dec 2024 18:13:29 +0000 Subject: [PATCH 15/19] Removing ability to recalculate SIT on address change approval --- pkg/handlers/ghcapi/api.go | 4 +- pkg/handlers/ghcapi/mto_service_items_test.go | 4 +- pkg/handlers/ghcapi/mto_shipment_test.go | 4 +- pkg/handlers/primeapi/api.go | 2 +- .../primeapi/mto_service_item_test.go | 4 +- pkg/handlers/supportapi/api.go | 2 +- .../supportapi/mto_service_item_test.go | 6 +- .../move_history/move_history_fetcher_test.go | 2 +- .../mto_service_item_updater.go | 68 ++++--------------- .../mto_service_item_updater_test.go | 6 +- .../shipment_address_update_requester.go | 9 +-- .../sit_extension/sit_extension_denier.go | 2 +- pkg/testdatagen/scenario/shared.go | 6 +- 13 files changed, 34 insertions(+), 85 deletions(-) diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index e16f557c890..fb928a203a3 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -236,7 +236,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { ghcAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{ HandlerConfig: handlerConfig, - MTOServiceItemUpdater: mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + MTOServiceItemUpdater: mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), Fetcher: fetch.NewFetcher(queryBuilder), ShipmentSITStatus: sitstatus.NewShipmentSITStatus(), MTOShipmentFetcher: mtoshipment.NewMTOShipmentFetcher(), @@ -506,7 +506,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { ghcAPI.ShipmentUpdateSITServiceItemCustomerExpenseHandler = UpdateSITServiceItemCustomerExpenseHandler{ handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), mtoshipment.NewMTOShipmentFetcher(), shipmentSITStatus, } diff --git a/pkg/handlers/ghcapi/mto_service_items_test.go b/pkg/handlers/ghcapi/mto_service_items_test.go index 551cd316c28..26c513d24a7 100644 --- a/pkg/handlers/ghcapi/mto_service_items_test.go +++ b/pkg/handlers/ghcapi/mto_service_items_test.go @@ -563,7 +563,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := UpdateMTOServiceItemStatusHandler{ HandlerConfig: suite.HandlerConfig(), @@ -623,7 +623,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + mtoServiceItemStatusUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) handler := UpdateMTOServiceItemStatusHandler{ HandlerConfig: suite.HandlerConfig(), diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go index 10da9753524..4baa9af8e63 100644 --- a/pkg/handlers/ghcapi/mto_shipment_test.go +++ b/pkg/handlers/ghcapi/mto_shipment_test.go @@ -4661,7 +4661,7 @@ func (suite *HandlerSuite) TestUpdateSITServiceItemCustomerExpenseHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) req := httptest.NewRequest("PATCH", fmt.Sprintf("/shipments/%s/sit-service-item/convert-to-customer-expense", approvedShipment.ID.String()), nil) req = suite.AuthenticateOfficeRequest(req, officeUser) handlerConfig := suite.HandlerConfig() @@ -4737,7 +4737,7 @@ func (suite *HandlerSuite) TestUpdateSITServiceItemCustomerExpenseHandler() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) req := httptest.NewRequest("PATCH", fmt.Sprintf("/shipments/%s/sit-service-item/convert-to-customer-expense", approvedShipment.ID.String()), nil) req = suite.AuthenticateOfficeRequest(req, officeUser) handlerConfig := suite.HandlerConfig() diff --git a/pkg/handlers/primeapi/api.go b/pkg/handlers/primeapi/api.go index 25afdb43b77..8c9492369b7 100644 --- a/pkg/handlers/primeapi/api.go +++ b/pkg/handlers/primeapi/api.go @@ -45,7 +45,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP shipmentFetcher := mtoshipment.NewMTOShipmentFetcher() moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()) uploadCreator := upload.NewUploadCreator(handlerConfig.FileStorer()) - serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) userUploader, err := uploader.NewUserUploader(handlerConfig.FileStorer(), uploader.MaxCustomerUserUploadFileSizeLimit) if err != nil { diff --git a/pkg/handlers/primeapi/mto_service_item_test.go b/pkg/handlers/primeapi/mto_service_item_test.go index 83b894bbab4..783efd3563f 100644 --- a/pkg/handlers/primeapi/mto_service_item_test.go +++ b/pkg/handlers/primeapi/mto_service_item_test.go @@ -1543,7 +1543,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemDDDSIT() { ).Return(400, nil) subtestData.handler = UpdateMTOServiceItemHandler{ suite.HandlerConfig(), - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), } // create the params struct @@ -1825,7 +1825,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemDOPSIT() { ).Return(400, nil) subtestData.handler = UpdateMTOServiceItemHandler{ suite.HandlerConfig(), - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), } // create the params struct diff --git a/pkg/handlers/supportapi/api.go b/pkg/handlers/supportapi/api.go index 1aba70b9c72..58c16043d0b 100644 --- a/pkg/handlers/supportapi/api.go +++ b/pkg/handlers/supportapi/api.go @@ -88,7 +88,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler { mtoserviceitem.NewMTOServiceItemCreator(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), handlerConfig.HHGPlanner()), } - supportAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{handlerConfig, mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer())} + supportAPI.MtoServiceItemUpdateMTOServiceItemStatusHandler = UpdateMTOServiceItemStatusHandler{handlerConfig, mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer())} supportAPI.WebhookReceiveWebhookNotificationHandler = ReceiveWebhookNotificationHandler{handlerConfig} // Create TAC and LOA services diff --git a/pkg/handlers/supportapi/mto_service_item_test.go b/pkg/handlers/supportapi/mto_service_item_test.go index 5db466e8d52..873d8ac0494 100644 --- a/pkg/handlers/supportapi/mto_service_item_test.go +++ b/pkg/handlers/supportapi/mto_service_item_test.go @@ -86,7 +86,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandlerApproveSuccess() mock.Anything, ).Return(400, nil) handler := UpdateMTOServiceItemStatusHandler{handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), } // CALL FUNCTION UNDER TEST @@ -142,7 +142,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandlerRejectSuccess() mock.Anything, ).Return(400, nil) handler := UpdateMTOServiceItemStatusHandler{handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), } // CALL FUNCTION UNDER TEST @@ -198,7 +198,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandlerRejectionFailedN mock.Anything, ).Return(400, nil) handler := UpdateMTOServiceItemStatusHandler{handlerConfig, - mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()), + mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()), } // CALL FUNCTION UNDER TEST diff --git a/pkg/services/move_history/move_history_fetcher_test.go b/pkg/services/move_history/move_history_fetcher_test.go index 3706ec214eb..f90d2ebc7f4 100644 --- a/pkg/services/move_history/move_history_fetcher_test.go +++ b/pkg/services/move_history/move_history_fetcher_test.go @@ -374,7 +374,7 @@ func (suite *MoveHistoryServiceSuite) TestMoveHistoryFetcherScenarios() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + updater := mtoserviceitem.NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) move := factory.BuildApprovalsRequestedMove(suite.DB(), nil, nil) serviceItem := factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ { diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 037c53c1da3..19adf509c64 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -39,28 +39,26 @@ type mtoServiceItemQueryBuilder interface { } type mtoServiceItemUpdater struct { - planner route.Planner - builder mtoServiceItemQueryBuilder - createNewBuilder func() mtoServiceItemQueryBuilder - moveRouter services.MoveRouter - shipmentFetcher services.MTOShipmentFetcher - addressCreator services.AddressCreator - unpackPricer services.DomesticUnpackPricer - linehaulPricer services.DomesticLinehaulPricer - destinationPricer services.DomesticDestinationPricer - fuelSurchargePricer services.FuelSurchargePricer - sitFuelSurchargePricer services.DomesticDestinationSITFuelSurchargePricer - sitDeliverPricer services.DomesticDestinationSITDeliveryPricer + planner route.Planner + builder mtoServiceItemQueryBuilder + createNewBuilder func() mtoServiceItemQueryBuilder + moveRouter services.MoveRouter + shipmentFetcher services.MTOShipmentFetcher + addressCreator services.AddressCreator + unpackPricer services.DomesticUnpackPricer + linehaulPricer services.DomesticLinehaulPricer + destinationPricer services.DomesticDestinationPricer + fuelSurchargePricer services.FuelSurchargePricer } // NewMTOServiceItemUpdater returns a new mto service item updater -func NewMTOServiceItemUpdater(planner route.Planner, builder mtoServiceItemQueryBuilder, moveRouter services.MoveRouter, shipmentFetcher services.MTOShipmentFetcher, addressCreator services.AddressCreator, unpackPricer services.DomesticUnpackPricer, linehaulPricer services.DomesticLinehaulPricer, destinationPricer services.DomesticDestinationPricer, fuelSurchargePricer services.FuelSurchargePricer, domesticDestinationSITDeliveryPricer services.DomesticDestinationSITDeliveryPricer, domesticDestinationSITFuelSurchargePricer services.DomesticDestinationSITFuelSurchargePricer) services.MTOServiceItemUpdater { +func NewMTOServiceItemUpdater(planner route.Planner, builder mtoServiceItemQueryBuilder, moveRouter services.MoveRouter, shipmentFetcher services.MTOShipmentFetcher, addressCreator services.AddressCreator, unpackPricer services.DomesticUnpackPricer, linehaulPricer services.DomesticLinehaulPricer, destinationPricer services.DomesticDestinationPricer, fuelSurchargePricer services.FuelSurchargePricer) services.MTOServiceItemUpdater { // used inside a transaction and mocking return &mtoServiceItemUpdater{builder: builder} createNewBuilder := func() mtoServiceItemQueryBuilder { return query.NewQueryBuilder() } - return &mtoServiceItemUpdater{planner, builder, createNewBuilder, moveRouter, shipmentFetcher, addressCreator, unpackPricer, linehaulPricer, destinationPricer, fuelSurchargePricer, domesticDestinationSITFuelSurchargePricer, domesticDestinationSITDeliveryPricer} + return &mtoServiceItemUpdater{planner, builder, createNewBuilder, moveRouter, shipmentFetcher, addressCreator, unpackPricer, linehaulPricer, destinationPricer, fuelSurchargePricer} } func (p *mtoServiceItemUpdater) ApproveOrRejectServiceItem( @@ -229,48 +227,6 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - // destination sit delivery - if serviceItem.ReService.Code == models.ReServiceCodeDDDSIT && serviceItem.SITDestinationFinalAddress != nil { - domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) - if err != nil { - return 0, err - } - if mtoShipment.DestinationAddress != nil { - distance, err = p.planner.ZipTransitDistance(appCtx, serviceItem.SITDestinationFinalAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) - if err != nil { - return 0, err - } - } - price, _, err = p.sitDeliverPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, domesticServiceArea.ServiceArea, domesticServiceArea.SITPDSchedule, mtoShipment.DestinationAddress.PostalCode, serviceItem.SITDestinationFinalAddress.PostalCode, unit.Miles(distance)) - if err != nil { - return 0, err - } - } - // destination sit fuel surcharge - if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC && serviceItem.SITDestinationFinalAddress != nil { - if mtoShipment.DestinationAddress != nil { - distance, err = p.planner.ZipTransitDistance(appCtx, serviceItem.SITDestinationFinalAddress.PostalCode, mtoShipment.DestinationAddress.PostalCode) - if err != nil { - return 0, err - } - } - fscWeightBasedDistanceMultiplier, err := LookupFSCWeightBasedDistanceMultiplier(appCtx, shipmentWeight) - if err != nil { - return 0, err - } - fscWeightBasedDistanceMultiplierFloat, err := strconv.ParseFloat(fscWeightBasedDistanceMultiplier, 64) - if err != nil { - return 0, err - } - eiaFuelPrice, err := LookupEIAFuelPrice(appCtx, *pickupDate) - if err != nil { - return 0, err - } - price, _, err = p.sitFuelSurchargePricer.Price(appCtx, *mtoShipment.ActualPickupDate, unit.Miles(distance), shipmentWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) - if err != nil { - return 0, err - } - } // fuel surcharge if serviceItem.ReService.Code == models.ReServiceCodeFSC { if mtoShipment.PickupAddress != nil && mtoShipment.DestinationAddress != nil { diff --git a/pkg/services/mto_service_item/mto_service_item_updater_test.go b/pkg/services/mto_service_item/mto_service_item_updater_test.go index 1baffb834e4..3d32c88c5df 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater_test.go +++ b/pkg/services/mto_service_item/mto_service_item_updater_test.go @@ -49,7 +49,7 @@ func (suite *MTOServiceItemServiceSuite) TestMTOServiceItemUpdater() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) setupServiceItem := func() (models.MTOServiceItem, string) { serviceItem := testdatagen.MakeDefaultMTOServiceItem(suite.DB()) @@ -1758,7 +1758,7 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemStatus() { mock.Anything, mock.Anything, ).Return(400, nil) - updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) rejectionReason := models.StringPointer("") @@ -2401,7 +2401,7 @@ func (suite *MTOServiceItemServiceSuite) TestUpdateMTOServiceItemPricingEstimate mock.Anything, mock.Anything, ).Return(400, nil) - updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + updater := NewMTOServiceItemUpdater(planner, builder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) setupServiceItem := func() (models.MTOServiceItem, string) { serviceItem := testdatagen.MakeDefaultMTOServiceItem(suite.DB()) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index ae2ef7ceb03..56a5e176e4f 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -465,7 +465,7 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc if tooApprovalStatus == models.ShipmentAddressUpdateStatusApproved { queryBuilder := query.NewQueryBuilder() - serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(f.planner, queryBuilder, f.moveRouter, f.shipmentFetcher, f.addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(f.planner, queryBuilder, f.moveRouter, f.shipmentFetcher, f.addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) serviceItemCreator := mtoserviceitem.NewMTOServiceItemCreator(f.planner, queryBuilder, f.moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) addressUpdate.Status = models.ShipmentAddressUpdateStatusApproved @@ -516,13 +516,6 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) } } - } else { - if serviceItem.ReService.Code == models.ReServiceCodeDDSFSC || serviceItem.ReService.Code == models.ReServiceCodeDDDSIT { - updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt)) - if err != nil { - return nil, apperror.NewUpdateError(serviceItem.ReServiceID, err.Error()) - } - } } if updatedServiceItem != nil { diff --git a/pkg/services/sit_extension/sit_extension_denier.go b/pkg/services/sit_extension/sit_extension_denier.go index bc0ddf8c100..735bc619db3 100644 --- a/pkg/services/sit_extension/sit_extension_denier.go +++ b/pkg/services/sit_extension/sit_extension_denier.go @@ -34,7 +34,7 @@ func NewSITExtensionDenier(moveRouter services.MoveRouter) services.SITExtension mock.Anything, mock.Anything, ).Return(400, nil) - return &sitExtensionDenier{moveRouter, mtoserviceitem.NewMTOServiceItemUpdater(planner, query.NewQueryBuilder(), moveRouter, mtoshipment.NewMTOShipmentFetcher(), address.NewAddressCreator(), ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer())} + return &sitExtensionDenier{moveRouter, mtoserviceitem.NewMTOServiceItemUpdater(planner, query.NewQueryBuilder(), moveRouter, mtoshipment.NewMTOShipmentFetcher(), address.NewAddressCreator(), ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer())} } // DenySITExtension denies the SIT Extension diff --git a/pkg/testdatagen/scenario/shared.go b/pkg/testdatagen/scenario/shared.go index e39b3b3a564..9890dbd126b 100644 --- a/pkg/testdatagen/scenario/shared.go +++ b/pkg/testdatagen/scenario/shared.go @@ -4274,7 +4274,7 @@ func createHHGWithOriginSITServiceItems( mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) var originFirstDaySIT models.MTOServiceItem var originAdditionalDaySIT models.MTOServiceItem @@ -4535,7 +4535,7 @@ func createHHGWithDestinationSITServiceItems(appCtx appcontext.AppContext, prime mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + serviceItemUpdator := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) var destinationFirstDaySIT models.MTOServiceItem var destinationAdditionalDaySIT models.MTOServiceItem @@ -5014,7 +5014,7 @@ func createHHGWithPaymentServiceItems( mock.Anything, mock.Anything, ).Return(400, nil) - serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer(), ghcrateengine.NewDomesticDestinationSITDeliveryPricer(), ghcrateengine.NewDomesticOriginSITFuelSurchargePricer()) + serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(planner, queryBuilder, moveRouter, shipmentFetcher, addressCreator, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer()) var originFirstDaySIT models.MTOServiceItem var originAdditionalDaySIT models.MTOServiceItem From 5b882c0fc9946dec125ae301837be828b1248808 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Fri, 31 Jan 2025 14:33:01 +0000 Subject: [PATCH 16/19] Removing Duplicate --- .../mto_service_item/mto_service_item_updater.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 650964dcaa4..986eb246250 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -186,20 +186,6 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - if serviceItem.ReService.Code == models.ReServiceCodeDUPK { - domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.DestinationAddress.PostalCode) - if err != nil { - return 0, err - } - - serviceScheduleDestination := domesticServiceArea.ServicesSchedule - - price, _, err = p.unpackPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, serviceScheduleDestination, isPPM) - if err != nil { - return 0, err - } - } - // linehaul if serviceItem.ReService.Code == models.ReServiceCodeDLH { domesticServiceArea, err := fetchDomesticServiceArea(appCtx, contractCode, mtoShipment.PickupAddress.PostalCode) From 40c8b9dc23244ad5f25647c914386c2f8210e4b7 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Fri, 31 Jan 2025 16:03:01 +0000 Subject: [PATCH 17/19] Updating pricing to use 110% weight --- .../mto_service_item_updater.go | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index 986eb246250..b3db491e050 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -181,7 +181,8 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, } } - price, _, err = p.destinationPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, domesticServiceArea.ServiceArea, isPPM) + adjustedWeight := GetAdjustedWeight(shipmentWeight, mtoShipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage) + price, _, err = p.destinationPricer.Price(appCtx, contractCode, *pickupDate, *adjustedWeight, domesticServiceArea.ServiceArea, isPPM) if err != nil { return 0, err } @@ -198,7 +199,9 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, return 0, err } } - price, _, err = p.linehaulPricer.Price(appCtx, contractCode, *pickupDate, unit.Miles(distance), shipmentWeight, domesticServiceArea.ServiceArea, isPPM) + + adjustedWeight := GetAdjustedWeight(shipmentWeight, mtoShipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage) + price, _, err = p.linehaulPricer.Price(appCtx, contractCode, *pickupDate, unit.Miles(distance), *adjustedWeight, domesticServiceArea.ServiceArea, isPPM) if err != nil { return 0, err } @@ -209,7 +212,9 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - price, _, err = p.unpackPricer.Price(appCtx, contractCode, *pickupDate, shipmentWeight, domesticServiceArea.ServicesSchedule, isPPM) + + adjustedWeight := GetAdjustedWeight(shipmentWeight, mtoShipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage) + price, _, err = p.unpackPricer.Price(appCtx, contractCode, *pickupDate, *adjustedWeight, domesticServiceArea.ServicesSchedule, isPPM) if err != nil { return 0, err } @@ -235,7 +240,9 @@ func (p *mtoServiceItemUpdater) findEstimatedPrice(appCtx appcontext.AppContext, if err != nil { return 0, err } - price, _, err = p.fuelSurchargePricer.Price(appCtx, *pickupDate, unit.Miles(distance), shipmentWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) + + adjustedWeight := GetAdjustedWeight(shipmentWeight, mtoShipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage) + price, _, err = p.fuelSurchargePricer.Price(appCtx, *pickupDate, unit.Miles(distance), *adjustedWeight, fscWeightBasedDistanceMultiplierFloat, eiaFuelPrice, isPPM) if err != nil { return 0, err } @@ -814,3 +821,22 @@ func ValidateUpdateMTOServiceItem(appCtx appcontext.AppContext, serviceItemData return newServiceItem, 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 +} From a63e374e0b5aa337bfc559f679cd29152c62f2be Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Fri, 31 Jan 2025 10:29:58 -0600 Subject: [PATCH 18/19] removing duplicate call --- .../mto_service_item_updater.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pkg/services/mto_service_item/mto_service_item_updater.go b/pkg/services/mto_service_item/mto_service_item_updater.go index b3db491e050..1bc9a64ec85 100644 --- a/pkg/services/mto_service_item/mto_service_item_updater.go +++ b/pkg/services/mto_service_item/mto_service_item_updater.go @@ -821,22 +821,3 @@ func ValidateUpdateMTOServiceItem(appCtx appcontext.AppContext, serviceItemData return newServiceItem, 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 -} From 6799a3f7f114f9b5e4a14e09fc72758c11506fe7 Mon Sep 17 00:00:00 2001 From: Cory Kleinjan Date: Thu, 20 Feb 2025 16:23:45 +0000 Subject: [PATCH 19/19] Adding in line removed by merge --- .../shipment_address_update_requester.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/shipment_address_update/shipment_address_update_requester.go b/pkg/services/shipment_address_update/shipment_address_update_requester.go index b4ccbf82b8f..0cb8ba3c123 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -534,7 +534,7 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc shipmentHasApprovedDestSIT := f.doesShipmentContainApprovedDestinationSIT(shipmentDetails) for i, serviceItem := range shipmentDetails.MTOServiceItems { - if shipment.PrimeEstimatedWeight != nil || shipment.PrimeActualWeight != nil { + if shipment.MarketCode != models.MarketCodeInternational && shipment.PrimeEstimatedWeight != nil || shipment.MarketCode != models.MarketCodeInternational && shipment.PrimeActualWeight != nil { var updatedServiceItem *models.MTOServiceItem if serviceItem.ReService.Code == models.ReServiceCodeDDP || serviceItem.ReService.Code == models.ReServiceCodeDUPK { updatedServiceItem, err = serviceItemUpdater.UpdateMTOServiceItemPricingEstimate(appCtx, &serviceItem, shipment, etag.GenerateEtag(serviceItem.UpdatedAt))