Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B-21378: Introduce iUB RDD Transit Calculation #14563

Merged
merged 45 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
086bc54
required delivery date is populated on ub shipments
TevinAdams Jan 10, 2025
f45bddf
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 10, 2025
a691148
comment adjustment
TevinAdams Jan 10, 2025
92108da
Fixing spaces
TevinAdams Jan 10, 2025
35e109c
Test adjustments
TevinAdams Jan 10, 2025
36ec311
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 10, 2025
aa28760
Condition adjustment
TevinAdams Jan 13, 2025
baddfd6
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 13, 2025
31b8bea
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 14, 2025
2d24eef
Adding hhgTransit logic
TevinAdams Jan 14, 2025
98ba6e4
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 14, 2025
571374c
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 15, 2025
6d031d7
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 16, 2025
f251caf
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 16, 2025
316ff03
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 21, 2025
b8c7d88
Refactor
TevinAdams Jan 21, 2025
75c3193
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 21, 2025
a8a122b
Typo in sql query
TevinAdams Jan 22, 2025
99c433f
Test adjustments
TevinAdams Jan 22, 2025
f8ecaa0
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 22, 2025
4a67b7e
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 22, 2025
48a2836
Error message edit
TevinAdams Jan 22, 2025
c94d52a
Remove logic from rules
TevinAdams Jan 22, 2025
b9eebe6
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 22, 2025
bd892c6
Additional test coverage
TevinAdams Jan 22, 2025
4399ac7
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 23, 2025
ceb6460
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 23, 2025
9d5727f
Typo in code
TevinAdams Jan 23, 2025
1bd1bbb
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 23, 2025
deab95a
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 24, 2025
bcbbd0a
Adding test coverage
TevinAdams Jan 24, 2025
9f01040
Additional Test Coverage
TevinAdams Jan 24, 2025
2614b71
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 27, 2025
8120482
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 27, 2025
7b389f7
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 28, 2025
6307f9a
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 28, 2025
bcac7ad
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 29, 2025
f09b742
Fixing tests for Intl transit RDD
TevinAdams Jan 29, 2025
9f73020
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 29, 2025
eafe4d8
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 29, 2025
c7b23b6
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 29, 2025
61c33c3
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 29, 2025
1ca36b8
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 30, 2025
951fb52
Test Adjustment
TevinAdams Jan 30, 2025
2e1f83a
Merge branch 'integrationTesting' into B-21378-iUB-RDD-Transit-Calcul…
TevinAdams Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions pkg/factory/mto_shipment_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,11 @@ func buildMTOShipmentWithBuildType(db *pop.Connection, customs []Customization,

if shipmentHasPickupDetails {
newMTOShipment.RequestedPickupDate = models.TimePointer(time.Date(GHCTestYear, time.March, 15, 0, 0, 0, 0, time.UTC))
newMTOShipment.ScheduledPickupDate = models.TimePointer(time.Date(GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC))
if cMtoShipment.ScheduledPickupDate == nil {
newMTOShipment.ScheduledPickupDate = models.TimePointer(time.Date(GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC))
} else {
newMTOShipment.ScheduledPickupDate = cMtoShipment.ScheduledPickupDate
}
newMTOShipment.ActualPickupDate = models.TimePointer(time.Date(GHCTestYear, time.March, 16, 0, 0, 0, 0, time.UTC))
}

Expand Down Expand Up @@ -208,8 +212,12 @@ func buildMTOShipmentWithBuildType(db *pop.Connection, customs []Customization,
}

if cMtoShipment.ScheduledPickupDate != nil {
requiredDeliveryDate := time.Date(GHCTestYear, time.April, 15, 0, 0, 0, 0, time.UTC)
newMTOShipment.RequiredDeliveryDate = &requiredDeliveryDate
if cMtoShipment.RequiredDeliveryDate != nil {
newMTOShipment.RequiredDeliveryDate = cMtoShipment.RequiredDeliveryDate
} else {
requiredDeliveryDate := time.Date(GHCTestYear, time.April, 15, 0, 0, 0, 0, time.UTC)
newMTOShipment.RequiredDeliveryDate = &requiredDeliveryDate
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/primeapiv3/mto_shipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func (h UpdateMTOShipmentHandler) Handle(params mtoshipmentops.UpdateMTOShipment
payloads.ClientError(handlers.PreconditionErrMessage, err.Error(), h.GetTraceIDFromRequest(params.HTTPRequest))), err
default:
return mtoshipmentops.NewUpdateMTOShipmentInternalServerError().WithPayload(
payloads.InternalServerError(nil, h.GetTraceIDFromRequest(params.HTTPRequest))), err
payloads.InternalServerError(handlers.FmtString(err.Error()), h.GetTraceIDFromRequest(params.HTTPRequest))), err
}
}
mtoShipmentPayload := payloads.MTOShipment(mtoShipment)
Expand Down
14 changes: 14 additions & 0 deletions pkg/models/re_contract_year.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ func (r *ReContractYear) Validate(_ *pop.Connection) (*validate.Errors, error) {
), nil
}

// This function uses a raw query that calls db function get_contract to get the reContractYearId in respects to the requestedPickupDate
func FetchContractId(db *pop.Connection, requestedPickupDate time.Time) (uuid.UUID, error) {
if !requestedPickupDate.IsZero() {
var reContractYearId uuid.UUID
err := db.RawQuery("SELECT get_contract_id($1)", requestedPickupDate).First(&reContractYearId)
if err != nil {
return uuid.Nil, fmt.Errorf("error fetching contract year id for requested pickup date %s", requestedPickupDate)
}

return reContractYearId, nil
}
return uuid.Nil, fmt.Errorf("error fetching contract ID - required parameters not provided")
}

func GetExpectedEscalationPriceContractsCount(contractYearName string) (ExpectedEscalationPriceContractsCount, error) {
switch contractYearName {
case BasePeriodYear1:
Expand Down
60 changes: 60 additions & 0 deletions pkg/models/re_contract_year_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/gofrs/uuid"

"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/testdatagen"
)

func (suite *ModelSuite) TestReContractYearValidations() {
Expand Down Expand Up @@ -52,3 +53,62 @@ func (suite *ModelSuite) TestReContractYearValidations() {
suite.verifyValidationErrors(&badDatesReContractYear, expErrors)
})
}

func (suite *ModelSuite) TestReContractYearModel() {
suite.Run("test that FetchContractId returns the contractId given a requestedPickupDate", func() {
validReContractYear := testdatagen.MakeReContractYear(suite.DB(), testdatagen.Assertions{
ReContractYear: models.ReContractYear{
Name: "Base Period Year 1",
StartDate: time.Date(2019, time.October, 1, 0, 0, 0, 0, time.UTC),
EndDate: time.Date(2020, time.September, 30, 0, 0, 0, 0, time.UTC),
Escalation: 1.03,
EscalationCompounded: 1.74,
},
})

requestedPickupDate := time.Date(2019, time.October, 25, 0, 0, 0, 0, time.UTC)
contractYearId, err := models.FetchContractId(suite.DB(), requestedPickupDate)

suite.Nil(err)
suite.NotNil(contractYearId)
suite.Equal(contractYearId, validReContractYear.ContractID)
})

suite.Run("test that FetchContractId returns error when no requestedPickupDate is given", func() {
testdatagen.MakeReContractYear(suite.DB(), testdatagen.Assertions{
ReContractYear: models.ReContractYear{
Name: "Base Period Year 1",
StartDate: time.Date(2019, time.October, 1, 0, 0, 0, 0, time.UTC),
EndDate: time.Date(2020, time.September, 30, 0, 0, 0, 0, time.UTC),
Escalation: 1.03,
EscalationCompounded: 1.74,
},
})

var time time.Time
contractYearId, err := models.FetchContractId(suite.DB(), time)

suite.NotNil(err)
suite.Contains(err.Error(), "error fetching contract ID - required parameters not provided")
suite.Equal(contractYearId, uuid.Nil)
})

suite.Run("test that FetchContractId returns error when no contract is found for given requestedPickupDate", func() {
testdatagen.MakeReContractYear(suite.DB(), testdatagen.Assertions{
ReContractYear: models.ReContractYear{
Name: "Base Period Year 1",
StartDate: time.Date(2019, time.October, 1, 0, 0, 0, 0, time.UTC),
EndDate: time.Date(2020, time.September, 30, 0, 0, 0, 0, time.UTC),
Escalation: 1.03,
EscalationCompounded: 1.74,
},
})
requestedPickupDate := time.Date(2019, time.September, 1, 0, 0, 0, 0, time.UTC)

contractYearId, err := models.FetchContractId(suite.DB(), requestedPickupDate)

suite.NotNil(err)
suite.Contains(err.Error(), "error fetching contract year id")
suite.Equal(contractYearId, uuid.Nil)
})
}
17 changes: 17 additions & 0 deletions pkg/models/re_intl_transit_times.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package models
import (
"time"

"github.com/gobuffalo/pop/v6"
"github.com/gofrs/uuid"

"github.com/transcom/mymove/pkg/apperror"
)

type InternationalTransitTime struct {
Expand All @@ -20,3 +23,17 @@ type InternationalTransitTime struct {
func (InternationalTransitTime) TableName() string {
return "re_intl_transit_times"
}

// fetch the re_intl_transit_time record from the db
func FetchInternationalTransitTime(db *pop.Connection, originRateAreaId uuid.UUID, destinationRateAreaId uuid.UUID) (InternationalTransitTime, error) {
var internationalTransitTime InternationalTransitTime
err := db.
Where("origin_rate_area_id = $1 and destination_rate_area_id = $2", originRateAreaId, destinationRateAreaId).
First(&internationalTransitTime)

if err != nil {
return internationalTransitTime, apperror.NewQueryError("InternationalTransitTime", err, "could not look up intl transit time")
}

return internationalTransitTime, nil
}
21 changes: 21 additions & 0 deletions pkg/models/re_intl_transit_times_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package models_test

import (
"github.com/gofrs/uuid"

"github.com/transcom/mymove/pkg/models"
)

func (suite *ModelSuite) TestIntlTransitTimesModel() {
suite.Run("test that FetchInternationalTransitTime returns the re_intl_transit_times given an originRateAreaId and a destinationRateAreaId", func() {
originRateAreaId := uuid.FromStringOrNil("6e802149-7e46-4d7a-ab57-6c4df832085d")
destinationRateAreaId := uuid.FromStringOrNil("c18e25f9-ec34-41ca-8c1b-05558c8d6364")

fetchedIntlTransitTime, err := models.FetchInternationalTransitTime(suite.DB(), originRateAreaId, destinationRateAreaId)

suite.Nil(err)
suite.NotNil(fetchedIntlTransitTime)
suite.Equal(originRateAreaId, fetchedIntlTransitTime.OriginRateAreaId)
suite.Equal(destinationRateAreaId, fetchedIntlTransitTime.DestinationRateAreaId)
})
}
7 changes: 5 additions & 2 deletions pkg/models/re_rate_area_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ func (suite *ModelSuite) TestFetchRateAreaID() {
})

suite.Run("fail - receive error when not all values are provided", func() {
address := factory.BuildAddress(suite.DB(), nil, nil)
rateAreaId, err := models.FetchRateAreaID(suite.DB(), address.ID, nil, uuid.Nil)
var nilUuid uuid.UUID
nonNilUuid := uuid.Must(uuid.NewV4())
contract := testdatagen.FetchOrMakeReContract(suite.DB(), testdatagen.Assertions{})
rateAreaId, err := models.FetchRateAreaID(suite.DB(), nilUuid, &nonNilUuid, contract.ID)

suite.Equal(uuid.Nil, rateAreaId)
suite.Error(err)
})
Expand Down
53 changes: 53 additions & 0 deletions pkg/services/mto_shipment/mto_shipment_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,16 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext,
newShipment = models.DetermineShipmentMarketCode(newShipment)
}

// RDD for UB shipments only need the pick up date, shipment origin address and destination address to determine required delivery date
if newShipment.ScheduledPickupDate != nil && !newShipment.ScheduledPickupDate.IsZero() && newShipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage {
calculatedRDD, err := CalculateRequiredDeliveryDateForInternationalShipment(appCtx, *newShipment.PickupAddress, *newShipment.DestinationAddress, *newShipment.ScheduledPickupDate, newShipment.ShipmentType)
if err != nil {
return err
}

newShipment.RequiredDeliveryDate = &calculatedRDD
}

if err := txnAppCtx.DB().Update(newShipment); err != nil {
return err
}
Expand Down Expand Up @@ -1042,6 +1052,7 @@ func (o *mtoShipmentStatusUpdater) createShipmentServiceItems(appCtx appcontext.
func (o *mtoShipmentStatusUpdater) setRequiredDeliveryDate(appCtx appcontext.AppContext, shipment *models.MTOShipment) error {
if shipment.ScheduledPickupDate != nil &&
shipment.RequiredDeliveryDate == nil &&
shipment.ShipmentType != models.MTOShipmentTypeUnaccompaniedBaggage &&
(shipment.PrimeEstimatedWeight != nil || shipment.NTSRecordedWeight != nil) {

var pickupLocation *models.Address
Expand Down Expand Up @@ -1081,6 +1092,13 @@ func (o *mtoShipmentStatusUpdater) setRequiredDeliveryDate(appCtx appcontext.App
}

shipment.RequiredDeliveryDate = requiredDeliveryDate
} else if shipment.ShipmentType == models.MTOShipmentTypeUnaccompaniedBaggage && shipment.ScheduledPickupDate != nil && !shipment.ScheduledDeliveryDate.IsZero() {
requiredDeliveryDate, calcErr := CalculateRequiredDeliveryDateForInternationalShipment(appCtx, *shipment.PickupAddress, *shipment.DestinationAddress, *shipment.ScheduledPickupDate, shipment.ShipmentType)
if calcErr != nil {
return calcErr
}

shipment.RequiredDeliveryDate = &requiredDeliveryDate
}

return nil
Expand Down Expand Up @@ -1273,6 +1291,41 @@ func CalculateRequiredDeliveryDate(appCtx appcontext.AppContext, planner route.P
return &requiredDeliveryDate, nil
}

// CalculateRequiredDeliveryDateForInternationalShipment function is used to get the Required delivery Date of a UB shipment by finding the re_intl_transit_time using the origin and destination address rate areas.
// The transit time is then added to the day after the pickup date then that date is used as the required delivery date for the UB shipment.
func CalculateRequiredDeliveryDateForInternationalShipment(appCtx appcontext.AppContext, pickupAddress models.Address, destinationAddress models.Address, pickupDate time.Time, shipmentType models.MTOShipmentType) (time.Time, error) {

// Transit times does not include the pickup date. Setting the required delivery date to the day after pickup date
rdd := pickupDate.AddDate(0, 0, 1)

// get the contract id
contractID, err := models.FetchContractId(appCtx.DB(), pickupDate)
if err != nil {
return rdd, err
}

// get the rate area id for the origin address
originRateAreaID, err := models.FetchRateAreaID(appCtx.DB(), pickupAddress.ID, nil, contractID)
if err != nil {
return rdd, err
}

// get the rate area id for the destination address
destRateAreaID, err := models.FetchRateAreaID(appCtx.DB(), destinationAddress.ID, nil, contractID)
if err != nil {
return rdd, err
}

// lookup the intl transit time
internationalTransitTime, err := models.FetchInternationalTransitTime(appCtx.DB(), originRateAreaID, destRateAreaID)
if err != nil {
return rdd, err
}

// rdd plus the intl ub transit time
return rdd.AddDate(0, 0, *internationalTransitTime.UbTransitTime), nil
}

// This private function is used to generically construct service items when shipments are approved.
func constructMTOServiceItemModels(shipmentID uuid.UUID, mtoID uuid.UUID, reServiceCodes []models.ReServiceCode) models.MTOServiceItems {
serviceItems := make(models.MTOServiceItems, len(reServiceCodes))
Expand Down
Loading