diff --git a/cmd/generate-shipment-summary/main.go b/cmd/generate-shipment-summary/main.go index e920d423276..c2a10a5c43c 100644 --- a/cmd/generate-shipment-summary/main.go +++ b/cmd/generate-shipment-summary/main.go @@ -19,7 +19,10 @@ import ( "github.com/transcom/mymove/pkg/cli" "github.com/transcom/mymove/pkg/logging" "github.com/transcom/mymove/pkg/paperwork" + paymentrequesthelper "github.com/transcom/mymove/pkg/payment_request" "github.com/transcom/mymove/pkg/route" + ppmcloseout "github.com/transcom/mymove/pkg/services/ppm_closeout" + "github.com/transcom/mymove/pkg/services/ppmshipment" shipmentsummaryworksheet "github.com/transcom/mymove/pkg/services/shipment_summary_worksheet" "github.com/transcom/mymove/pkg/storage" "github.com/transcom/mymove/pkg/uploader" @@ -148,7 +151,11 @@ func main() { // TODO: Future cleanup will need to remap to a different planner, but this command should remain for testing purposes planner := route.NewHEREPlanner(hereClient, geocodeEndpoint, routingEndpoint, testAppID, testAppCode) - ppmComputer := shipmentsummaryworksheet.NewSSWPPMComputer() + ppmEstimator := ppmshipment.NewEstimatePPM(planner, &paymentrequesthelper.RequestPaymentHelper{}) + + ppmCloseoutFetcher := ppmcloseout.NewPPMCloseoutFetcher(planner, &paymentrequesthelper.RequestPaymentHelper{}, ppmEstimator) + + ppmComputer := shipmentsummaryworksheet.NewSSWPPMComputer(ppmCloseoutFetcher) ssfd, err := ppmComputer.FetchDataShipmentSummaryWorksheetFormData(appCtx, &auth.Session{}, parsedID) if err != nil { diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index 2066bae9d15..79a58ad3ad6 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -81,7 +81,9 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { moveRouter, signedCertificationCreator, signedCertificationUpdater, ) - SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer() + ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) + ppmCloseoutFetcher := ppmcloseout.NewPPMCloseoutFetcher(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}, ppmEstimator) + SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer(ppmCloseoutFetcher) uploadCreator := upload.NewUploadCreator(handlerConfig.FileStorer()) userUploader, err := uploader.NewUserUploader(handlerConfig.FileStorer(), uploader.MaxCustomerUserUploadFileSizeLimit) @@ -198,7 +200,6 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { ) paymentRequestShipmentRecalculator := paymentrequest.NewPaymentRequestShipmentRecalculator(paymentRequestRecalculator) addressUpdater := address.NewAddressUpdater() - ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) ppmShipmentUpdater := ppmshipment.NewPPMShipmentUpdater(ppmEstimator, addressCreator, addressUpdater) boatShipmentUpdater := boatshipment.NewBoatShipmentUpdater() mobileHomeShipmentUpdater := mobileHomeShipment.NewMobileHomeShipmentUpdater() @@ -569,8 +570,6 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { ppmDocumentsFetcher, } - ppmCloseoutFetcher := ppmcloseout.NewPPMCloseoutFetcher(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}, ppmEstimator) - ghcAPI.PpmGetPPMCloseoutHandler = GetPPMCloseoutHandler{ handlerConfig, ppmCloseoutFetcher, diff --git a/pkg/handlers/internalapi/api.go b/pkg/handlers/internalapi/api.go index bdcf857225e..91673f1f838 100644 --- a/pkg/handlers/internalapi/api.go +++ b/pkg/handlers/internalapi/api.go @@ -31,6 +31,7 @@ import ( "github.com/transcom/mymove/pkg/services/paperwork" paymentrequest "github.com/transcom/mymove/pkg/services/payment_request" postalcodeservice "github.com/transcom/mymove/pkg/services/postal_codes" + ppmcloseout "github.com/transcom/mymove/pkg/services/ppm_closeout" "github.com/transcom/mymove/pkg/services/ppmshipment" progear "github.com/transcom/mymove/pkg/services/progear_weight_ticket" "github.com/transcom/mymove/pkg/services/query" @@ -57,7 +58,9 @@ func NewInternalAPI(handlerConfig handlers.HandlerConfig) *internalops.MymoveAPI fetcher := fetch.NewFetcher(builder) moveRouter := move.NewMoveRouter() uploadCreator := upload.NewUploadCreator(handlerConfig.FileStorer()) - SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer() + ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) + ppmCloseoutFetcher := ppmcloseout.NewPPMCloseoutFetcher(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}, ppmEstimator) + SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer(ppmCloseoutFetcher) userUploader, err := uploader.NewUserUploader(handlerConfig.FileStorer(), uploader.MaxCustomerUserUploadFileSizeLimit) if err != nil { @@ -81,7 +84,6 @@ func NewInternalAPI(handlerConfig handlers.HandlerConfig) *internalops.MymoveAPI log.Fatalln(err) } - ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}) signedCertificationCreator := signedcertification.NewSignedCertificationCreator() signedCertificationUpdater := signedcertification.NewSignedCertificationUpdater() mtoShipmentRouter := mtoshipment.NewShipmentRouter() diff --git a/pkg/models/worksheet_shipment.go b/pkg/models/worksheet_shipment.go new file mode 100644 index 00000000000..3097ac15e52 --- /dev/null +++ b/pkg/models/worksheet_shipment.go @@ -0,0 +1,72 @@ +package models + +import ( + "time" + + "github.com/transcom/mymove/pkg/unit" +) + +// WorkSheetShipments is an object representing shipment line items on Shipment Summary Worksheet +type WorkSheetShipments struct { + ShipmentNumberAndTypes string + PickUpDates string + ShipmentWeights string + ShipmentWeightForObligation string + CurrentShipmentStatuses string +} + +// WorkSheetShipment is an object representing specific shipment items on Shipment Summary Worksheet +type WorkSheetShipment struct { + EstimatedIncentive string + MaxAdvance string + FinalIncentive string + AdvanceAmountReceived string + ShipmentNumberAndTypes string + PickUpDates string + ShipmentWeights string + ShipmentWeightForObligation string + CurrentShipmentStatuses string +} + +// SSWMaxWeightEntitlement weight allotment for the shipment summary worksheet. +type SSWMaxWeightEntitlement struct { + Entitlement unit.Pound + ProGear unit.Pound + SpouseProGear unit.Pound + TotalWeight unit.Pound +} + +// Obligations is an object representing the winning and non-winning Max Obligation and Actual Obligation sections of the shipment summary worksheet +type Obligations struct { + MaxObligation Obligation + ActualObligation Obligation + NonWinningMaxObligation Obligation + NonWinningActualObligation Obligation +} + +// Obligation an object representing the obligations section on the shipment summary worksheet +type Obligation struct { + Gcc unit.Cents + SIT unit.Cents + Miles unit.Miles +} + +// ShipmentSummaryFormData is a container for the various objects required for the a Shipment Summary Worksheet +type ShipmentSummaryFormData struct { + ServiceMember ServiceMember + Order Order + Move Move + CurrentDutyLocation DutyLocation + NewDutyLocation DutyLocation + WeightAllotment SSWMaxWeightEntitlement + PPMShipment PPMShipment + PPMShipments PPMShipments + PPMShipmentFinalWeight unit.Pound + W2Address *Address + PreparationDate time.Time + Obligations Obligations + MovingExpenses MovingExpenses + PPMRemainingEntitlement float64 + SignedCertifications []*SignedCertification + MaxSITStorageEntitlement int +} diff --git a/pkg/services/mocks/SSWPPMComputer.go b/pkg/services/mocks/SSWPPMComputer.go index 23372677ec1..51d71821328 100644 --- a/pkg/services/mocks/SSWPPMComputer.go +++ b/pkg/services/mocks/SSWPPMComputer.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" + models "github.com/transcom/mymove/pkg/models" + route "github.com/transcom/mymove/pkg/route" services "github.com/transcom/mymove/pkg/services" @@ -21,21 +23,21 @@ type SSWPPMComputer struct { } // ComputeObligations provides a mock function with given fields: _a0, _a1, _a2 -func (_m *SSWPPMComputer) ComputeObligations(_a0 appcontext.AppContext, _a1 services.ShipmentSummaryFormData, _a2 route.Planner) (services.Obligations, error) { +func (_m *SSWPPMComputer) ComputeObligations(_a0 appcontext.AppContext, _a1 models.ShipmentSummaryFormData, _a2 route.Planner) (models.Obligations, error) { ret := _m.Called(_a0, _a1, _a2) - var r0 services.Obligations + var r0 models.Obligations var r1 error - if rf, ok := ret.Get(0).(func(appcontext.AppContext, services.ShipmentSummaryFormData, route.Planner) (services.Obligations, error)); ok { + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.ShipmentSummaryFormData, route.Planner) (models.Obligations, error)); ok { return rf(_a0, _a1, _a2) } - if rf, ok := ret.Get(0).(func(appcontext.AppContext, services.ShipmentSummaryFormData, route.Planner) services.Obligations); ok { + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.ShipmentSummaryFormData, route.Planner) models.Obligations); ok { r0 = rf(_a0, _a1, _a2) } else { - r0 = ret.Get(0).(services.Obligations) + r0 = ret.Get(0).(models.Obligations) } - if rf, ok := ret.Get(1).(func(appcontext.AppContext, services.ShipmentSummaryFormData, route.Planner) error); ok { + if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.ShipmentSummaryFormData, route.Planner) error); ok { r1 = rf(_a0, _a1, _a2) } else { r1 = ret.Error(1) @@ -45,19 +47,19 @@ func (_m *SSWPPMComputer) ComputeObligations(_a0 appcontext.AppContext, _a1 serv } // FetchDataShipmentSummaryWorksheetFormData provides a mock function with given fields: appCtx, _a1, ppmShipmentID -func (_m *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData(appCtx appcontext.AppContext, _a1 *auth.Session, ppmShipmentID uuid.UUID) (*services.ShipmentSummaryFormData, error) { +func (_m *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData(appCtx appcontext.AppContext, _a1 *auth.Session, ppmShipmentID uuid.UUID) (*models.ShipmentSummaryFormData, error) { ret := _m.Called(appCtx, _a1, ppmShipmentID) - var r0 *services.ShipmentSummaryFormData + var r0 *models.ShipmentSummaryFormData var r1 error - if rf, ok := ret.Get(0).(func(appcontext.AppContext, *auth.Session, uuid.UUID) (*services.ShipmentSummaryFormData, error)); ok { + if rf, ok := ret.Get(0).(func(appcontext.AppContext, *auth.Session, uuid.UUID) (*models.ShipmentSummaryFormData, error)); ok { return rf(appCtx, _a1, ppmShipmentID) } - if rf, ok := ret.Get(0).(func(appcontext.AppContext, *auth.Session, uuid.UUID) *services.ShipmentSummaryFormData); ok { + if rf, ok := ret.Get(0).(func(appcontext.AppContext, *auth.Session, uuid.UUID) *models.ShipmentSummaryFormData); ok { r0 = rf(appCtx, _a1, ppmShipmentID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*services.ShipmentSummaryFormData) + r0 = ret.Get(0).(*models.ShipmentSummaryFormData) } } @@ -70,29 +72,43 @@ func (_m *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData(appCtx appco return r0, r1 } +// FormatShipment provides a mock function with given fields: ppm, weightAllotment, isPaymentPacket +func (_m *SSWPPMComputer) FormatShipment(ppm models.PPMShipment, weightAllotment models.SSWMaxWeightEntitlement, isPaymentPacket bool) models.WorkSheetShipment { + ret := _m.Called(ppm, weightAllotment, isPaymentPacket) + + var r0 models.WorkSheetShipment + if rf, ok := ret.Get(0).(func(models.PPMShipment, models.SSWMaxWeightEntitlement, bool) models.WorkSheetShipment); ok { + r0 = rf(ppm, weightAllotment, isPaymentPacket) + } else { + r0 = ret.Get(0).(models.WorkSheetShipment) + } + + return r0 +} + // FormatValuesShipmentSummaryWorksheet provides a mock function with given fields: shipmentSummaryFormData, isPaymentPacket -func (_m *SSWPPMComputer) FormatValuesShipmentSummaryWorksheet(shipmentSummaryFormData services.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, services.Page2Values, error) { +func (_m *SSWPPMComputer) FormatValuesShipmentSummaryWorksheet(shipmentSummaryFormData models.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, services.Page2Values, error) { ret := _m.Called(shipmentSummaryFormData, isPaymentPacket) var r0 services.Page1Values var r1 services.Page2Values var r2 error - if rf, ok := ret.Get(0).(func(services.ShipmentSummaryFormData, bool) (services.Page1Values, services.Page2Values, error)); ok { + if rf, ok := ret.Get(0).(func(models.ShipmentSummaryFormData, bool) (services.Page1Values, services.Page2Values, error)); ok { return rf(shipmentSummaryFormData, isPaymentPacket) } - if rf, ok := ret.Get(0).(func(services.ShipmentSummaryFormData, bool) services.Page1Values); ok { + if rf, ok := ret.Get(0).(func(models.ShipmentSummaryFormData, bool) services.Page1Values); ok { r0 = rf(shipmentSummaryFormData, isPaymentPacket) } else { r0 = ret.Get(0).(services.Page1Values) } - if rf, ok := ret.Get(1).(func(services.ShipmentSummaryFormData, bool) services.Page2Values); ok { + if rf, ok := ret.Get(1).(func(models.ShipmentSummaryFormData, bool) services.Page2Values); ok { r1 = rf(shipmentSummaryFormData, isPaymentPacket) } else { r1 = ret.Get(1).(services.Page2Values) } - if rf, ok := ret.Get(2).(func(services.ShipmentSummaryFormData, bool) error); ok { + if rf, ok := ret.Get(2).(func(models.ShipmentSummaryFormData, bool) error); ok { r2 = rf(shipmentSummaryFormData, isPaymentPacket) } else { r2 = ret.Error(2) @@ -101,6 +117,54 @@ func (_m *SSWPPMComputer) FormatValuesShipmentSummaryWorksheet(shipmentSummaryFo return r0, r1, r2 } +// FormatValuesShipmentSummaryWorksheetFormPage1 provides a mock function with given fields: data, isPaymentPacket +func (_m *SSWPPMComputer) FormatValuesShipmentSummaryWorksheetFormPage1(data models.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, error) { + ret := _m.Called(data, isPaymentPacket) + + var r0 services.Page1Values + var r1 error + if rf, ok := ret.Get(0).(func(models.ShipmentSummaryFormData, bool) (services.Page1Values, error)); ok { + return rf(data, isPaymentPacket) + } + if rf, ok := ret.Get(0).(func(models.ShipmentSummaryFormData, bool) services.Page1Values); ok { + r0 = rf(data, isPaymentPacket) + } else { + r0 = ret.Get(0).(services.Page1Values) + } + + if rf, ok := ret.Get(1).(func(models.ShipmentSummaryFormData, bool) error); ok { + r1 = rf(data, isPaymentPacket) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FormatValuesShipmentSummaryWorksheetFormPage2 provides a mock function with given fields: data, isPaymentPacket +func (_m *SSWPPMComputer) FormatValuesShipmentSummaryWorksheetFormPage2(data models.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page2Values, error) { + ret := _m.Called(data, isPaymentPacket) + + var r0 services.Page2Values + var r1 error + if rf, ok := ret.Get(0).(func(models.ShipmentSummaryFormData, bool) (services.Page2Values, error)); ok { + return rf(data, isPaymentPacket) + } + if rf, ok := ret.Get(0).(func(models.ShipmentSummaryFormData, bool) services.Page2Values); ok { + r0 = rf(data, isPaymentPacket) + } else { + r0 = ret.Get(0).(services.Page2Values) + } + + if rf, ok := ret.Get(1).(func(models.ShipmentSummaryFormData, bool) error); ok { + r1 = rf(data, isPaymentPacket) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // NewSSWPPMComputer creates a new instance of SSWPPMComputer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewSSWPPMComputer(t interface { diff --git a/pkg/services/ppmshipment/aoa_packet_creator_test.go b/pkg/services/ppmshipment/aoa_packet_creator_test.go index 8dedea7a2b5..437e3c20d91 100644 --- a/pkg/services/ppmshipment/aoa_packet_creator_test.go +++ b/pkg/services/ppmshipment/aoa_packet_creator_test.go @@ -162,7 +162,8 @@ func (suite *PPMShipmentSuite) TestCreateAOAPacketFull() { suite.FatalNil(err) } - SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer() + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + SSWPPMComputer := shipmentsummaryworksheet.NewSSWPPMComputer(mockPPMCloseoutFetcher) ppmGenerator, err := shipmentsummaryworksheet.NewSSWPPMGenerator(generator) suite.FatalNoError(err) diff --git a/pkg/services/shipment_summary_worksheet.go b/pkg/services/shipment_summary_worksheet.go index 1f2d38fadf6..feec76938f6 100644 --- a/pkg/services/shipment_summary_worksheet.go +++ b/pkg/services/shipment_summary_worksheet.go @@ -1,8 +1,6 @@ package services import ( - "time" - "github.com/gofrs/uuid" "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" "github.com/spf13/afero" @@ -11,7 +9,6 @@ import ( "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/route" - "github.com/transcom/mymove/pkg/unit" ) // Dollar represents a type for dollar monetary unit @@ -135,54 +132,14 @@ type FormattedMovingExpenses struct { TotalPaidSIT string } -// ShipmentSummaryFormData is a container for the various objects required for the a Shipment Summary Worksheet -type ShipmentSummaryFormData struct { - ServiceMember models.ServiceMember - Order models.Order - Move models.Move - CurrentDutyLocation models.DutyLocation - NewDutyLocation models.DutyLocation - WeightAllotment SSWMaxWeightEntitlement - PPMShipment models.PPMShipment - PPMShipments models.PPMShipments - PPMShipmentFinalWeight unit.Pound - W2Address *models.Address - PreparationDate time.Time - Obligations Obligations - MovingExpenses models.MovingExpenses - PPMRemainingEntitlement float64 - SignedCertifications []*models.SignedCertification - MaxSITStorageEntitlement int -} - -// Obligations is an object representing the winning and non-winning Max Obligation and Actual Obligation sections of the shipment summary worksheet -type Obligations struct { - MaxObligation Obligation - ActualObligation Obligation - NonWinningMaxObligation Obligation - NonWinningActualObligation Obligation -} - -// Obligation an object representing the obligations section on the shipment summary worksheet -type Obligation struct { - Gcc unit.Cents - SIT unit.Cents - Miles unit.Miles -} - -// SSWMaxWeightEntitlement weight allotment for the shipment summary worksheet. -type SSWMaxWeightEntitlement struct { - Entitlement unit.Pound - ProGear unit.Pound - SpouseProGear unit.Pound - TotalWeight unit.Pound -} - //go:generate mockery --name SSWPPMComputer type SSWPPMComputer interface { - FetchDataShipmentSummaryWorksheetFormData(appCtx appcontext.AppContext, _ *auth.Session, ppmShipmentID uuid.UUID) (*ShipmentSummaryFormData, error) - ComputeObligations(_ appcontext.AppContext, _ ShipmentSummaryFormData, _ route.Planner) (Obligations, error) - FormatValuesShipmentSummaryWorksheet(shipmentSummaryFormData ShipmentSummaryFormData, isPaymentPacket bool) (Page1Values, Page2Values, error) + FetchDataShipmentSummaryWorksheetFormData(appCtx appcontext.AppContext, _ *auth.Session, ppmShipmentID uuid.UUID) (*models.ShipmentSummaryFormData, error) + ComputeObligations(_ appcontext.AppContext, _ models.ShipmentSummaryFormData, _ route.Planner) (models.Obligations, error) + FormatValuesShipmentSummaryWorksheet(shipmentSummaryFormData models.ShipmentSummaryFormData, isPaymentPacket bool) (Page1Values, Page2Values, error) + FormatShipment(ppm models.PPMShipment, weightAllotment models.SSWMaxWeightEntitlement, isPaymentPacket bool) models.WorkSheetShipment + FormatValuesShipmentSummaryWorksheetFormPage1(data models.ShipmentSummaryFormData, isPaymentPacket bool) (Page1Values, error) + FormatValuesShipmentSummaryWorksheetFormPage2(data models.ShipmentSummaryFormData, isPaymentPacket bool) (Page2Values, error) } //go:generate mockery --name SSWPPMGenerator diff --git a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go index 6c2ad909284..c3e68499e45 100644 --- a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go +++ b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go @@ -29,11 +29,14 @@ import ( // SSWPPMComputer is the concrete struct implementing the services.shipmentsummaryworksheet interface type SSWPPMComputer struct { + services.PPMCloseoutFetcher } // NewSSWPPMComputer creates a SSWPPMComputer -func NewSSWPPMComputer() services.SSWPPMComputer { - return &SSWPPMComputer{} +func NewSSWPPMComputer(ppmCloseoutFetcher services.PPMCloseoutFetcher) services.SSWPPMComputer { + return &SSWPPMComputer{ + ppmCloseoutFetcher, + } } // SSWPPMGenerator is the concrete struct implementing the services.shipmentsummaryworksheet interface @@ -56,16 +59,15 @@ func NewSSWPPMGenerator(pdfGenerator *paperwork.Generator) (services.SSWPPMGener } // FormatValuesShipmentSummaryWorksheet returns the formatted pages for the Shipment Summary Worksheet -func (SSWPPMComputer *SSWPPMComputer) FormatValuesShipmentSummaryWorksheet(shipmentSummaryFormData services.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, services.Page2Values, error) { - page1, err := FormatValuesShipmentSummaryWorksheetFormPage1(shipmentSummaryFormData, isPaymentPacket) +func (SSWPPMComputer *SSWPPMComputer) FormatValuesShipmentSummaryWorksheet(shipmentSummaryFormData models.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, services.Page2Values, error) { + page1, err := SSWPPMComputer.FormatValuesShipmentSummaryWorksheetFormPage1(shipmentSummaryFormData, isPaymentPacket) if err != nil { return page1, services.Page2Values{}, errors.WithStack(err) } - page2, err := FormatValuesShipmentSummaryWorksheetFormPage2(shipmentSummaryFormData, isPaymentPacket) + page2, err := SSWPPMComputer.FormatValuesShipmentSummaryWorksheetFormPage2(shipmentSummaryFormData, isPaymentPacket) if err != nil { return page1, page2, errors.WithStack(err) } - return page1, page2, nil } @@ -79,19 +81,6 @@ type textField struct { Locked bool `json:"locked"` } -// WorkSheetShipment is an object representing specific shipment items on Shipment Summary Worksheet -type WorkSheetShipment struct { - EstimatedIncentive string - MaxAdvance string - FinalIncentive string - AdvanceAmountReceived string - ShipmentNumberAndTypes string - PickUpDates string - ShipmentWeights string - ShipmentWeightForObligation string - CurrentShipmentStatuses string -} - // WorkSheetSIT is an object representing SIT on the Shipment Summary Worksheet type WorkSheetSIT struct { NumberAndTypes string @@ -162,17 +151,17 @@ func (wa *SSWMaxWeightEntitlement) addLineItem(field string, value int) { // SSWGetEntitlement calculates the entitlement for the shipment summary worksheet based on the parameters of // a move (hasDependents, spouseHasProGear) -func SSWGetEntitlement(grade internalmessages.OrderPayGrade, hasDependents bool, spouseHasProGear bool) services.SSWMaxWeightEntitlement { +func SSWGetEntitlement(grade internalmessages.OrderPayGrade, hasDependents bool, spouseHasProGear bool) models.SSWMaxWeightEntitlement { sswEntitlements := SSWMaxWeightEntitlement{} entitlements := models.GetWeightAllotment(grade) sswEntitlements.addLineItem("ProGear", entitlements.ProGearWeight) sswEntitlements.addLineItem("SpouseProGear", entitlements.ProGearWeightSpouse) if !hasDependents { sswEntitlements.addLineItem("Entitlement", entitlements.TotalWeightSelf) - return services.SSWMaxWeightEntitlement(sswEntitlements) + return models.SSWMaxWeightEntitlement(sswEntitlements) } sswEntitlements.addLineItem("Entitlement", entitlements.TotalWeightSelfPlusDependents) - return services.SSWMaxWeightEntitlement(sswEntitlements) + return models.SSWMaxWeightEntitlement(sswEntitlements) } // CalculateRemainingPPMEntitlement calculates the remaining PPM entitlement for PPM moves @@ -202,7 +191,7 @@ const ( ) // FormatValuesShipmentSummaryWorksheetFormPage1 formats the data for page 1 of the Shipment Summary Worksheet -func FormatValuesShipmentSummaryWorksheetFormPage1(data services.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, error) { +func (s SSWPPMComputer) FormatValuesShipmentSummaryWorksheetFormPage1(data models.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page1Values, error) { var err error page1 := services.Page1Values{} page1.CUIBanner = controlledUnclassifiedInformationText @@ -235,7 +224,7 @@ func FormatValuesShipmentSummaryWorksheetFormPage1(data services.ShipmentSummary formattedSIT := WorkSheetSIT{} - formattedShipment := FormatShipment(data.PPMShipment, isPaymentPacket) + formattedShipment := s.FormatShipment(data.PPMShipment, data.WeightAllotment, isPaymentPacket) page1.ShipmentNumberAndTypes = formattedShipment.ShipmentNumberAndTypes page1.ShipmentPickUpDates = formattedShipment.PickUpDates page1.ShipmentCurrentShipmentStatuses = formattedShipment.CurrentShipmentStatuses @@ -255,7 +244,7 @@ func FormatValuesShipmentSummaryWorksheetFormPage1(data services.ShipmentSummary formattedSIT = FormatAllSITSForAOAPacket(data.PPMShipment) page1.ShipmentWeights = formattedShipment.ShipmentWeights - page1.ActualObligationGCC100 = formattedShipment.ShipmentWeightForObligation + " - Estimated lbs; " + formattedShipment.FinalIncentive + page1.ActualObligationGCC100 = formattedShipment.ShipmentWeightForObligation + " - Actual lbs; " page1.PreparationDate1 = formatAOADate(data.SignedCertifications, data.PPMShipment.ID) } @@ -276,11 +265,11 @@ func FormatValuesShipmentSummaryWorksheetFormPage1(data services.ShipmentSummary } // FormatValuesShipmentSummaryWorksheetFormPage2 formats the data for page 2 of the Shipment Summary Worksheet -func FormatValuesShipmentSummaryWorksheetFormPage2(data services.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page2Values, error) { +func (s *SSWPPMComputer) FormatValuesShipmentSummaryWorksheetFormPage2(data models.ShipmentSummaryFormData, isPaymentPacket bool) (services.Page2Values, error) { var err error expensesMap := SubTotalExpenses(data.MovingExpenses) certificationInfo := formatSignedCertifications(data.SignedCertifications, data.PPMShipment.ID, isPaymentPacket) - formattedShipments := FormatShipment(data.PPMShipment, isPaymentPacket) + formattedShipments := s.FormatShipment(data.PPMShipment, data.WeightAllotment, isPaymentPacket) page2 := services.Page2Values{} page2.CUIBanner = controlledUnclassifiedInformationText @@ -498,8 +487,8 @@ func FormatServiceMemberFullName(serviceMember models.ServiceMember) string { return strings.TrimSpace(fmt.Sprintf("%s, %s %s", lastName, firstName, middleName)) } -func FormatShipment(ppm models.PPMShipment, isPaymentPacket bool) WorkSheetShipment { - formattedShipment := WorkSheetShipment{} +func (s SSWPPMComputer) FormatShipment(ppm models.PPMShipment, weightAllotment models.SSWMaxWeightEntitlement, isPaymentPacket bool) models.WorkSheetShipment { + formattedShipment := models.WorkSheetShipment{} if ppm.FinalIncentive != nil { formattedShipment.FinalIncentive = FormatDollarFromCents(*ppm.FinalIncentive) @@ -523,7 +512,7 @@ func FormatShipment(ppm models.PPMShipment, isPaymentPacket bool) WorkSheetShipm formattedShipmentWeights := FormatPPMWeightEstimated(ppm) formattedShipmentStatuses := FormatCurrentPPMStatus(ppm) if ppm.EstimatedWeight != nil { - formattedShipmentTotalWeights += *ppm.EstimatedWeight + formattedShipmentTotalWeights += s.calculateShipmentTotalWeight(ppm, weightAllotment) } formattedPickUpDates := FormatDate(ppm.ExpectedDepartureDate) @@ -576,6 +565,35 @@ func FormatAllSITSForAOAPacket(ppm models.PPMShipment) WorkSheetSIT { return formattedSIT } +func (s SSWPPMComputer) calculateShipmentTotalWeight(ppmShipment models.PPMShipment, weightAllotment models.SSWMaxWeightEntitlement) unit.Pound { + + var err error + var ppmActualWeight unit.Pound + var maxLimit unit.Pound + + // Set maxLimit equal to the maximum weight entitlement or the allowable weight, whichever is lower + if weightAllotment.TotalWeight < weightAllotment.Entitlement { + maxLimit = weightAllotment.TotalWeight + } else { + maxLimit = weightAllotment.Entitlement + } + + // Get the actual weight of the ppmShipment + if len(ppmShipment.WeightTickets) > 0 { + ppmActualWeight, err = s.PPMCloseoutFetcher.GetActualWeight(&ppmShipment) + if err != nil { + return 0 + } + } + + // If actual weight is less than the lessor of maximum weight entitlement or the allowable weight, then use ppmActualWeight + if ppmActualWeight < maxLimit { + return ppmActualWeight + } else { + return maxLimit + } +} + // FetchMovingExpensesShipmentSummaryWorksheet fetches moving expenses for the Shipment Summary Worksheet // TODO: update to create moving expense summary with the new moving expense model func FetchMovingExpensesShipmentSummaryWorksheet(PPMShipment models.PPMShipment, _ appcontext.AppContext, _ *auth.Session) (models.MovingExpenses, error) { @@ -768,19 +786,19 @@ type ObligationType int // ComputeObligations is helper function for computing the obligations section of the shipment summary worksheet // Obligations must remain as static test data until new computer system is finished -func (SSWPPMComputer *SSWPPMComputer) ComputeObligations(_ appcontext.AppContext, _ services.ShipmentSummaryFormData, _ route.Planner) (obligation services.Obligations, err error) { +func (SSWPPMComputer *SSWPPMComputer) ComputeObligations(_ appcontext.AppContext, _ models.ShipmentSummaryFormData, _ route.Planner) (obligation models.Obligations, err error) { // Obligations must remain test data until new computer system is finished - obligations := services.Obligations{ - ActualObligation: services.Obligation{Gcc: 123, SIT: 123, Miles: unit.Miles(123456)}, - MaxObligation: services.Obligation{Gcc: 456, SIT: 456, Miles: unit.Miles(123456)}, - NonWinningActualObligation: services.Obligation{Gcc: 789, SIT: 789, Miles: unit.Miles(12345)}, - NonWinningMaxObligation: services.Obligation{Gcc: 1000, SIT: 1000, Miles: unit.Miles(12345)}, + obligations := models.Obligations{ + ActualObligation: models.Obligation{Gcc: 123, SIT: 123, Miles: unit.Miles(123456)}, + MaxObligation: models.Obligation{Gcc: 456, SIT: 456, Miles: unit.Miles(123456)}, + NonWinningActualObligation: models.Obligation{Gcc: 789, SIT: 789, Miles: unit.Miles(12345)}, + NonWinningMaxObligation: models.Obligation{Gcc: 1000, SIT: 1000, Miles: unit.Miles(12345)}, } return obligations, nil } // FetchDataShipmentSummaryWorksheetFormData fetches the pages for the Shipment Summary Worksheet for a given Move ID -func (SSWPPMComputer *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData(appCtx appcontext.AppContext, session *auth.Session, ppmShipmentID uuid.UUID) (*services.ShipmentSummaryFormData, error) { +func (SSWPPMComputer *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData(appCtx appcontext.AppContext, session *auth.Session, ppmShipmentID uuid.UUID) (*models.ShipmentSummaryFormData, error) { ppmShipment := models.PPMShipment{} dbQErr := appCtx.DB().Q().Eager( @@ -833,7 +851,7 @@ func (SSWPPMComputer *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData( if ppmShipment.Shipment.MoveTaskOrder.Orders.OriginDutyLocation == nil { return nil, errors.New("order for PPM shipment does not have a origin duty location attached") } - ssd := services.ShipmentSummaryFormData{ + ssd := models.ShipmentSummaryFormData{ ServiceMember: serviceMember, Order: ppmShipment.Shipment.MoveTaskOrder.Orders, Move: ppmShipment.Shipment.MoveTaskOrder, diff --git a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go index a793c684927..fe6286bb8ce 100644 --- a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go +++ b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go @@ -19,7 +19,7 @@ import ( "github.com/transcom/mymove/pkg/gen/internalmessages" "github.com/transcom/mymove/pkg/models" paperworkgenerator "github.com/transcom/mymove/pkg/paperwork" - "github.com/transcom/mymove/pkg/services" + "github.com/transcom/mymove/pkg/services/mocks" storageTest "github.com/transcom/mymove/pkg/storage/test" "github.com/transcom/mymove/pkg/unit" "github.com/transcom/mymove/pkg/uploader" @@ -31,7 +31,8 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW yuma := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) fortGordon := factory.FetchOrBuildOrdersDutyLocation(suite.DB()) grade := models.ServiceMemberGradeE9 - SSWPPMComputer := NewSSWPPMComputer() + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + SSWPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) ppmShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{ { @@ -110,7 +111,8 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW yuma := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) fortGordon := factory.FetchOrBuildOrdersDutyLocation(suite.DB()) grade := models.ServiceMemberGradeE9 - SSWPPMComputer := NewSSWPPMComputer() + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + SSWPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) move := factory.BuildMove(suite.DB(), []factory.Customization{ { @@ -216,7 +218,8 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW yuma := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) fortGordon := factory.FetchOrBuildOrdersDutyLocation(suite.DB()) grade := models.ServiceMemberGradeE9 - SSWPPMComputer := NewSSWPPMComputer() + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + SSWPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) ppmShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{ { @@ -277,7 +280,7 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatValuesShipmentSummaryWorksheetFormPage1() { yuma := factory.FetchOrBuildCurrentDutyLocation(suite.DB()) fortGordon := factory.FetchOrBuildOrdersDutyLocation(suite.DB()) - wtgEntitlements := services.SSWMaxWeightEntitlement{ + wtgEntitlements := models.SSWMaxWeightEntitlement{ Entitlement: 15000, ProGear: 2000, SpouseProGear: 500, @@ -328,7 +331,7 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatValuesShipmentSumma ShipmentLocator: &locator, }, } - ssd := services.ShipmentSummaryFormData{ + ssd := models.ShipmentSummaryFormData{ ServiceMember: serviceMember, Order: order, CurrentDutyLocation: yuma, @@ -338,8 +341,12 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatValuesShipmentSumma PreparationDate: time.Date(2019, 1, 1, 1, 1, 1, 1, time.UTC), PPMShipment: PPMShipments, } - sswPage1, err := FormatValuesShipmentSummaryWorksheetFormPage1(ssd, false) + + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + sswPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) + sswPage1, err := sswPPMComputer.FormatValuesShipmentSummaryWorksheetFormPage1(ssd, false) suite.NoError(err) + suite.Equal(FormatDate(time.Now()), sswPage1.PreparationDate1) suite.Equal("Jenkins Jr., Marcus Joseph", sswPage1.ServiceMemberName) suite.Equal("E-9", sswPage1.RankGrade) @@ -378,7 +385,7 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatValuesShipmentSumma }, } - ssdWithoutPPMActualMoveDate := services.ShipmentSummaryFormData{ + ssdWithoutPPMActualMoveDate := models.ShipmentSummaryFormData{ ServiceMember: serviceMember, Order: order, CurrentDutyLocation: yuma, @@ -388,7 +395,7 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatValuesShipmentSumma PreparationDate: time.Date(2019, 1, 1, 1, 1, 1, 1, time.UTC), PPMShipment: PPMShipmentWithoutActualMoveDate, } - sswPage1NoActualMoveDate, err := FormatValuesShipmentSummaryWorksheetFormPage1(ssdWithoutPPMActualMoveDate, false) + sswPage1NoActualMoveDate, err := sswPPMComputer.FormatValuesShipmentSummaryWorksheetFormPage1(ssdWithoutPPMActualMoveDate, false) suite.NoError(err) suite.Equal("N/A", sswPage1NoActualMoveDate.ShipmentPickUpDates) } @@ -456,13 +463,15 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatValuesShipmentSumma }, } - ssd := services.ShipmentSummaryFormData{ + ssd := models.ShipmentSummaryFormData{ Order: order, MovingExpenses: movingExpenses, PPMShipment: shipment, } - sswPage2, err := FormatValuesShipmentSummaryWorksheetFormPage2(ssd, false) + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + sswPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) + sswPage2, err := sswPPMComputer.FormatValuesShipmentSummaryWorksheetFormPage2(ssd, false) suite.NoError(err) suite.Equal("$200.00", sswPage2.TollsGTCCPaid) suite.Equal("$200.00", sswPage2.TollsMemberPaid) @@ -593,7 +602,16 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatShipmentNumberAndTy }, } - singlePPMFormatted := FormatShipment(singlePPM, false) + wtgEntitlements := models.SSWMaxWeightEntitlement{ + Entitlement: 15000, + ProGear: 2000, + SpouseProGear: 500, + TotalWeight: 17500, + } + + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + sswPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) + singlePPMFormatted := sswPPMComputer.FormatShipment(singlePPM, wtgEntitlements, false) // testing single shipment moves suite.Equal("ABCDEF-01", singlePPMFormatted.ShipmentNumberAndTypes) @@ -861,7 +879,8 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFillSSWPDFForm() { generator, err := paperworkgenerator.NewGenerator(userUploader.Uploader()) suite.FatalNil(err) - SSWPPMComputer := NewSSWPPMComputer() + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + sswPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) ppmGenerator, err := NewSSWPPMGenerator(generator) suite.FatalNoError(err) ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION @@ -914,9 +933,9 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFillSSWPDFForm() { models.SaveMoveDependencies(suite.DB(), &ppmShipment.Shipment.MoveTaskOrder) - ssd, err := SSWPPMComputer.FetchDataShipmentSummaryWorksheetFormData(suite.AppContextForTest(), &session, ppmShipmentID) + ssd, err := sswPPMComputer.FetchDataShipmentSummaryWorksheetFormData(suite.AppContextForTest(), &session, ppmShipmentID) suite.NoError(err) - page1Data, page2Data, err := SSWPPMComputer.FormatValuesShipmentSummaryWorksheet(*ssd, false) + page1Data, page2Data, err := sswPPMComputer.FormatValuesShipmentSummaryWorksheet(*ssd, false) suite.NoError(err) test, info, err := ppmGenerator.FillSSWPDFForm(page1Data, page2Data) suite.NoError(err) @@ -955,10 +974,19 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatShipment() { exampleValue2 := unit.Cents(3000) exampleValue3 := unit.Cents(1000) locator := "ABCDEF-01" + + wtgEntitlements := models.SSWMaxWeightEntitlement{ + Entitlement: 15000, + ProGear: 2000, + SpouseProGear: 500, + TotalWeight: 17500, + } + tests := []struct { name string shipment models.PPMShipment - expectedResult WorkSheetShipment + expectedResult models.WorkSheetShipment + entitlements models.SSWMaxWeightEntitlement }{ { name: "All fields present", @@ -970,13 +998,14 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatShipment() { ShipmentLocator: &locator, }, }, - expectedResult: WorkSheetShipment{ + expectedResult: models.WorkSheetShipment{ FinalIncentive: "$50.00", // Example expected result MaxAdvance: "$18.00", // Assuming formatMaxAdvance correctly formats EstimatedIncentive: "$30.00", // Example expected result AdvanceAmountReceived: "$10.00", // Example expected result ShipmentNumberAndTypes: locator, }, + entitlements: wtgEntitlements, }, { name: "Final Incentive nil", @@ -988,18 +1017,22 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatShipment() { ShipmentLocator: &locator, }, }, - expectedResult: WorkSheetShipment{ + expectedResult: models.WorkSheetShipment{ FinalIncentive: "No final incentive.", MaxAdvance: "$18.00", // Assuming formatMaxAdvance correctly formats EstimatedIncentive: "$30.00", // Example expected result AdvanceAmountReceived: "$10.00", // Example expected result ShipmentNumberAndTypes: locator, }, + entitlements: wtgEntitlements, }, } + mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{} + sswPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher) + for _, tt := range tests { - result := FormatShipment(tt.shipment, false) + result := sswPPMComputer.FormatShipment(tt.shipment, tt.entitlements, false) suite.Equal(tt.expectedResult.FinalIncentive, result.FinalIncentive) suite.Equal(tt.expectedResult.MaxAdvance, result.MaxAdvance)