From a265b88242dab94dfeafcff55a837e226b7a3951 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 25 Feb 2025 15:03:09 +0000 Subject: [PATCH 1/3] initial commit, added migrations, updated swagger, go structs, populating value on shipment creation --- .circleci/config.yml | 1 + .envrc | 1 + config/env/demo.app-client-tls.env | 1 + config/env/demo.app.env | 1 + config/env/exp.app-client-tls.env | 1 + config/env/exp.app.env | 1 + config/env/loadtest.app-client-tls.env | 1 + config/env/loadtest.app.env | 1 + config/env/prd.app-client-tls.env | 1 + config/env/prd.app.env | 1 + config/env/stg.app-client-tls.env | 1 + config/env/stg.app.env | 1 + .../flipt/storage/development.features.yaml | 16 ++++ .../20250224200700_tbl_ppm_shipments.up.sql | 3 + ...20250224202726_ty_ppm_shipment_type.up.sql | 11 +++ ...50224202738_ty_moving_expenses_type.up.sql | 2 + migrations/app/ddl_tables_manifest.txt | 1 + migrations/app/ddl_types_manifest.txt | 2 + pkg/factory/ppm_shipment_factory.go | 1 + pkg/gen/ghcapi/embedded_spec.go | 28 ++++++ pkg/gen/ghcmessages/p_p_m_shipment.go | 46 ++++++++++ pkg/gen/ghcmessages/p_p_m_type.go | 92 +++++++++++++++++++ pkg/gen/internalapi/embedded_spec.go | 28 ++++++ pkg/gen/internalmessages/p_p_m_shipment.go | 46 ++++++++++ pkg/gen/internalmessages/p_p_m_type.go | 92 +++++++++++++++++++ pkg/models/moving_expense.go | 2 + pkg/models/ppm_shipment.go | 13 +++ .../ppmshipment/ppm_shipment_creator.go | 5 + .../ppmshipment/ppm_shipment_creator_test.go | 1 + src/shared/constants.js | 13 +++ swagger-def/definitions/PPMShipment.yaml | 2 + swagger-def/definitions/PPMType.yaml | 8 ++ swagger/ghc.yaml | 11 +++ swagger/internal.yaml | 11 +++ 34 files changed, 446 insertions(+) create mode 100644 migrations/app/ddl_migrations/ddl_tables/20250224200700_tbl_ppm_shipments.up.sql create mode 100644 migrations/app/ddl_migrations/ddl_types/20250224202726_ty_ppm_shipment_type.up.sql create mode 100644 migrations/app/ddl_migrations/ddl_types/20250224202738_ty_moving_expenses_type.up.sql create mode 100644 pkg/gen/ghcmessages/p_p_m_type.go create mode 100644 pkg/gen/internalmessages/p_p_m_type.go create mode 100644 swagger-def/definitions/PPMType.yaml diff --git a/.circleci/config.yml b/.circleci/config.yml index 7a4fb382a9e..bb76fc8fd5f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -883,6 +883,7 @@ commands: export ENVIRONMENT=test export FEATURE_FLAG_MULTI_MOVE=true export FEATURE_FLAG_PPM=true + export FEATURE_FLAG_PPM_SPR=false export FEATURE_FLAG_NTS=true export FEATURE_FLAG_NTSR=true export FEATURE_FLAG_BOAT=true diff --git a/.envrc b/.envrc index beb0b08ea1f..22374409701 100644 --- a/.envrc +++ b/.envrc @@ -166,6 +166,7 @@ export FEATURE_FLAG_QUEUE_MANAGEMENT=true # Feature flags to disable certain shipment types export FEATURE_FLAG_PPM=true +export FEATURE_FLAG_PPM_SPR=false export FEATURE_FLAG_NTS=true export FEATURE_FLAG_NTSR=true export FEATURE_FLAG_BOAT=true diff --git a/config/env/demo.app-client-tls.env b/config/env/demo.app-client-tls.env index 9990552dff2..5989ccfd533 100644 --- a/config/env/demo.app-client-tls.env +++ b/config/env/demo.app-client-tls.env @@ -32,6 +32,7 @@ TELEMETRY_USE_XRAY_ID=true TLS_ENABLED=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/demo.app.env b/config/env/demo.app.env index fae5faf098c..2621c72fb7a 100644 --- a/config/env/demo.app.env +++ b/config/env/demo.app.env @@ -37,6 +37,7 @@ SERVE_API_SUPPORT=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_COUNSELOR_MOVE_CREATE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/exp.app-client-tls.env b/config/env/exp.app-client-tls.env index 85f315e3173..706d0d7d7eb 100644 --- a/config/env/exp.app-client-tls.env +++ b/config/env/exp.app-client-tls.env @@ -32,6 +32,7 @@ TELEMETRY_ENDPOINT=localhost:4317 TELEMETRY_USE_XRAY_ID=false FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/exp.app.env b/config/env/exp.app.env index 43bb56f3c19..c425328db35 100644 --- a/config/env/exp.app.env +++ b/config/env/exp.app.env @@ -37,6 +37,7 @@ TELEMETRY_USE_XRAY_ID=true FEATURE_FLAG_MULTI_MOVE=true FEATURE_FLAG_COUNSELOR_MOVE_CREATE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/loadtest.app-client-tls.env b/config/env/loadtest.app-client-tls.env index b26524393e3..7f6b5d92528 100644 --- a/config/env/loadtest.app-client-tls.env +++ b/config/env/loadtest.app-client-tls.env @@ -30,6 +30,7 @@ TELEMETRY_USE_XRAY_ID=true TLS_ENABLED=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/loadtest.app.env b/config/env/loadtest.app.env index 6f2870f3826..1db3e2ea2ed 100644 --- a/config/env/loadtest.app.env +++ b/config/env/loadtest.app.env @@ -35,6 +35,7 @@ SERVE_API_SUPPORT=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_COUNSELOR_MOVE_CREATE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/prd.app-client-tls.env b/config/env/prd.app-client-tls.env index 9b754221581..c9d4a6228ed 100644 --- a/config/env/prd.app-client-tls.env +++ b/config/env/prd.app-client-tls.env @@ -29,6 +29,7 @@ TELEMETRY_USE_XRAY_ID=true TLS_ENABLED=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_PPM=false +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=false FEATURE_FLAG_NTSR=false FEATURE_FLAG_BOAT=false diff --git a/config/env/prd.app.env b/config/env/prd.app.env index be956f4a530..8d2fbc7c7a2 100644 --- a/config/env/prd.app.env +++ b/config/env/prd.app.env @@ -36,6 +36,7 @@ SERVE_API_SUPPORT=false FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_COUNSELOR_MOVE_CREATE=false FEATURE_FLAG_PPM=false +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=false FEATURE_FLAG_NTSR=false FEATURE_FLAG_BOAT=false diff --git a/config/env/stg.app-client-tls.env b/config/env/stg.app-client-tls.env index 7047aafebea..067e1e9bdd2 100644 --- a/config/env/stg.app-client-tls.env +++ b/config/env/stg.app-client-tls.env @@ -31,6 +31,7 @@ TELEMETRY_USE_XRAY_ID=true TLS_ENABLED=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/env/stg.app.env b/config/env/stg.app.env index 33ba71851ed..3228ea40103 100644 --- a/config/env/stg.app.env +++ b/config/env/stg.app.env @@ -37,6 +37,7 @@ SERVE_API_SUPPORT=true FEATURE_FLAG_MULTI_MOVE=false FEATURE_FLAG_COUNSELOR_MOVE_CREATE =false FEATURE_FLAG_PPM=true +FEATURE_FLAG_PPM_SPR=false FEATURE_FLAG_NTS=true FEATURE_FLAG_NTSR=true FEATURE_FLAG_BOAT=false diff --git a/config/flipt/storage/development.features.yaml b/config/flipt/storage/development.features.yaml index 224f763e922..cde89f09329 100644 --- a/config/flipt/storage/development.features.yaml +++ b/config/flipt/storage/development.features.yaml @@ -73,6 +73,14 @@ flags: - segment: key: mil-app value: false + - key: enable_hawaii + name: Enable Hawaii feature flag + type: BOOLEAN_FLAG_TYPE + enabled: false + rollouts: + - segment: + key: mil-app + value: false - key: okta_dodid_input name: Customer DODID input being pulled from Okta and disabling text input type: BOOLEAN_FLAG_TYPE @@ -89,6 +97,14 @@ flags: - segment: key: mil-app value: true + - key: ppm_spr + name: Enable PPM Small Package Reimbursement flag + type: BOOLEAN_FLAG_TYPE + enabled: false + rollouts: + - segment: + key: mil-app + value: false - key: nts name: NTS feature flag type: BOOLEAN_FLAG_TYPE diff --git a/migrations/app/ddl_migrations/ddl_tables/20250224200700_tbl_ppm_shipments.up.sql b/migrations/app/ddl_migrations/ddl_tables/20250224200700_tbl_ppm_shipments.up.sql new file mode 100644 index 00000000000..a23f7e68968 --- /dev/null +++ b/migrations/app/ddl_migrations/ddl_tables/20250224200700_tbl_ppm_shipments.up.sql @@ -0,0 +1,3 @@ +-- B-22653 Daniel Jordan add ppm_type column to ppm_shipments +ALTER TABLE ppm_shipments +ADD COLUMN IF NOT EXISTS ppm_type ppm_shipment_type NOT NULL DEFAULT 'INCENTIVE_BASED'; diff --git a/migrations/app/ddl_migrations/ddl_types/20250224202726_ty_ppm_shipment_type.up.sql b/migrations/app/ddl_migrations/ddl_types/20250224202726_ty_ppm_shipment_type.up.sql new file mode 100644 index 00000000000..8d06f35dec6 --- /dev/null +++ b/migrations/app/ddl_migrations/ddl_types/20250224202726_ty_ppm_shipment_type.up.sql @@ -0,0 +1,11 @@ +-- B-22653 Daniel Jordan add ppm_shipment_type +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'ppm_shipment_type') THEN + CREATE TYPE ppm_shipment_type AS ENUM ( + 'INCENTIVE_BASED', + 'ACTUAL_EXPENSE', + 'SMALL_PACKAGE' + ); + END IF; +END $$; diff --git a/migrations/app/ddl_migrations/ddl_types/20250224202738_ty_moving_expenses_type.up.sql b/migrations/app/ddl_migrations/ddl_types/20250224202738_ty_moving_expenses_type.up.sql new file mode 100644 index 00000000000..2cad6fed1f4 --- /dev/null +++ b/migrations/app/ddl_migrations/ddl_types/20250224202738_ty_moving_expenses_type.up.sql @@ -0,0 +1,2 @@ +-- B-22653 Daniel Jordan update moving_expense_type to include SMALL_PACKAGE +ALTER TYPE moving_expense_type ADD VALUE IF NOT EXISTS 'SMALL_PACKAGE'; \ No newline at end of file diff --git a/migrations/app/ddl_tables_manifest.txt b/migrations/app/ddl_tables_manifest.txt index 8fd6841c337..9de3cbf4e7e 100644 --- a/migrations/app/ddl_tables_manifest.txt +++ b/migrations/app/ddl_tables_manifest.txt @@ -1,3 +1,4 @@ # This is the tables migrations manifest. # If a migration is not recorded here, then it will error. # Naming convention: tbl_some_table.up.sql running will create this file. +20250224200700_tbl_ppm_shipments.up.sql diff --git a/migrations/app/ddl_types_manifest.txt b/migrations/app/ddl_types_manifest.txt index 9229c96f599..6faaa8a3f24 100644 --- a/migrations/app/ddl_types_manifest.txt +++ b/migrations/app/ddl_types_manifest.txt @@ -1,3 +1,5 @@ # This is the types migrations manifest. # If a migration is not recorded here, then it will error. # Naming convention: ty_some_type.up.sql running will create this file. +20250224202726_ty_ppm_shipment_type.up.sql +20250224202738_ty_moving_expenses_type.up.sql diff --git a/pkg/factory/ppm_shipment_factory.go b/pkg/factory/ppm_shipment_factory.go index cc87032285e..dc0cbe809c6 100644 --- a/pkg/factory/ppm_shipment_factory.go +++ b/pkg/factory/ppm_shipment_factory.go @@ -57,6 +57,7 @@ func buildPPMShipmentWithBuildType(db *pop.Connection, customs []Customization, } ppmShipment := models.PPMShipment{ + PPMType: models.PPMType(models.PPMTypeIncentiveBased), ShipmentID: shipment.ID, Shipment: shipment, Status: models.PPMShipmentStatusDraft, diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 3d41db0769c..3f9bea981ff 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -12320,6 +12320,9 @@ func init() { "pickupAddress": { "$ref": "#/definitions/Address" }, + "ppmType": { + "$ref": "#/definitions/PPMType" + }, "proGearWeight": { "description": "The estimated weight of the pro-gear being moved belonging to the service member.", "type": "integer", @@ -12534,6 +12537,17 @@ func init() { "COMPLETED" ] }, + "PPMType": { + "description": "Defines a PPM type", + "type": "string", + "title": "PPM Type", + "enum": [ + "INCENTIVE_BASED", + "ACTUAL_EXPENSE", + "SMALL_PACKAGE" + ], + "readOnly": true + }, "PWSViolation": { "description": "A PWS violation for an evaluation report", "type": "object", @@ -29916,6 +29930,9 @@ func init() { "pickupAddress": { "$ref": "#/definitions/Address" }, + "ppmType": { + "$ref": "#/definitions/PPMType" + }, "proGearWeight": { "description": "The estimated weight of the pro-gear being moved belonging to the service member.", "type": "integer", @@ -30130,6 +30147,17 @@ func init() { "COMPLETED" ] }, + "PPMType": { + "description": "Defines a PPM type", + "type": "string", + "title": "PPM Type", + "enum": [ + "INCENTIVE_BASED", + "ACTUAL_EXPENSE", + "SMALL_PACKAGE" + ], + "readOnly": true + }, "PWSViolation": { "description": "A PWS violation for an evaluation report", "type": "object", diff --git a/pkg/gen/ghcmessages/p_p_m_shipment.go b/pkg/gen/ghcmessages/p_p_m_shipment.go index 3b563ef0515..2b1228b27cf 100644 --- a/pkg/gen/ghcmessages/p_p_m_shipment.go +++ b/pkg/gen/ghcmessages/p_p_m_shipment.go @@ -136,6 +136,9 @@ type PPMShipment struct { // pickup address PickupAddress *Address `json:"pickupAddress,omitempty"` + // ppm type + PpmType PPMType `json:"ppmType,omitempty"` + // The estimated weight of the pro-gear being moved belonging to the service member. ProGearWeight *int64 `json:"proGearWeight"` @@ -272,6 +275,10 @@ func (m *PPMShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validatePpmType(formats); err != nil { + res = append(res, err) + } + if err := m.validateProGearWeightTickets(formats); err != nil { res = append(res, err) } @@ -537,6 +544,23 @@ func (m *PPMShipment) validatePickupAddress(formats strfmt.Registry) error { return nil } +func (m *PPMShipment) validatePpmType(formats strfmt.Registry) error { + if swag.IsZero(m.PpmType) { // not required + return nil + } + + if err := m.PpmType.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ppmType") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ppmType") + } + return err + } + + return nil +} + func (m *PPMShipment) validateProGearWeightTickets(formats strfmt.Registry) error { if swag.IsZero(m.ProGearWeightTickets) { // not required return nil @@ -849,6 +873,10 @@ func (m *PPMShipment) ContextValidate(ctx context.Context, formats strfmt.Regist res = append(res, err) } + if err := m.contextValidatePpmType(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateProGearWeightTickets(ctx, formats); err != nil { res = append(res, err) } @@ -1027,6 +1055,24 @@ func (m *PPMShipment) contextValidatePickupAddress(ctx context.Context, formats return nil } +func (m *PPMShipment) contextValidatePpmType(ctx context.Context, formats strfmt.Registry) error { + + if swag.IsZero(m.PpmType) { // not required + return nil + } + + if err := m.PpmType.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ppmType") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ppmType") + } + return err + } + + return nil +} + func (m *PPMShipment) contextValidateProGearWeightTickets(ctx context.Context, formats strfmt.Registry) error { for i := 0; i < len(m.ProGearWeightTickets); i++ { diff --git a/pkg/gen/ghcmessages/p_p_m_type.go b/pkg/gen/ghcmessages/p_p_m_type.go new file mode 100644 index 00000000000..eb16d8cdaf2 --- /dev/null +++ b/pkg/gen/ghcmessages/p_p_m_type.go @@ -0,0 +1,92 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ghcmessages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// PPMType PPM Type +// +// # Defines a PPM type +// +// swagger:model PPMType +type PPMType string + +func NewPPMType(value PPMType) *PPMType { + return &value +} + +// Pointer returns a pointer to a freshly-allocated PPMType. +func (m PPMType) Pointer() *PPMType { + return &m +} + +const ( + + // PPMTypeINCENTIVEBASED captures enum value "INCENTIVE_BASED" + PPMTypeINCENTIVEBASED PPMType = "INCENTIVE_BASED" + + // PPMTypeACTUALEXPENSE captures enum value "ACTUAL_EXPENSE" + PPMTypeACTUALEXPENSE PPMType = "ACTUAL_EXPENSE" + + // PPMTypeSMALLPACKAGE captures enum value "SMALL_PACKAGE" + PPMTypeSMALLPACKAGE PPMType = "SMALL_PACKAGE" +) + +// for schema +var pPMTypeEnum []interface{} + +func init() { + var res []PPMType + if err := json.Unmarshal([]byte(`["INCENTIVE_BASED","ACTUAL_EXPENSE","SMALL_PACKAGE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + pPMTypeEnum = append(pPMTypeEnum, v) + } +} + +func (m PPMType) validatePPMTypeEnum(path, location string, value PPMType) error { + if err := validate.EnumCase(path, location, value, pPMTypeEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this p p m type +func (m PPMType) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validatePPMTypeEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validate this p p m type based on the context it is used +func (m PPMType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := validate.ReadOnly(ctx, "", "body", PPMType(m)); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/gen/internalapi/embedded_spec.go b/pkg/gen/internalapi/embedded_spec.go index 35d92886247..7fe513dece1 100644 --- a/pkg/gen/internalapi/embedded_spec.go +++ b/pkg/gen/internalapi/embedded_spec.go @@ -6511,6 +6511,9 @@ func init() { "pickupAddress": { "$ref": "#/definitions/Address" }, + "ppmType": { + "$ref": "#/definitions/PPMType" + }, "proGearWeight": { "description": "The estimated weight of the pro-gear being moved belonging to the service member.", "type": "integer", @@ -6684,6 +6687,17 @@ func init() { ], "readOnly": true }, + "PPMType": { + "description": "Defines a PPM type", + "type": "string", + "title": "PPM Type", + "enum": [ + "INCENTIVE_BASED", + "ACTUAL_EXPENSE", + "SMALL_PACKAGE" + ], + "readOnly": true + }, "PatchMovePayload": { "type": "object", "required": [ @@ -15653,6 +15667,9 @@ func init() { "pickupAddress": { "$ref": "#/definitions/Address" }, + "ppmType": { + "$ref": "#/definitions/PPMType" + }, "proGearWeight": { "description": "The estimated weight of the pro-gear being moved belonging to the service member.", "type": "integer", @@ -15826,6 +15843,17 @@ func init() { ], "readOnly": true }, + "PPMType": { + "description": "Defines a PPM type", + "type": "string", + "title": "PPM Type", + "enum": [ + "INCENTIVE_BASED", + "ACTUAL_EXPENSE", + "SMALL_PACKAGE" + ], + "readOnly": true + }, "PatchMovePayload": { "type": "object", "required": [ diff --git a/pkg/gen/internalmessages/p_p_m_shipment.go b/pkg/gen/internalmessages/p_p_m_shipment.go index 43181ef2904..294a0608532 100644 --- a/pkg/gen/internalmessages/p_p_m_shipment.go +++ b/pkg/gen/internalmessages/p_p_m_shipment.go @@ -136,6 +136,9 @@ type PPMShipment struct { // pickup address PickupAddress *Address `json:"pickupAddress,omitempty"` + // ppm type + PpmType PPMType `json:"ppmType,omitempty"` + // The estimated weight of the pro-gear being moved belonging to the service member. ProGearWeight *int64 `json:"proGearWeight"` @@ -272,6 +275,10 @@ func (m *PPMShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validatePpmType(formats); err != nil { + res = append(res, err) + } + if err := m.validateProGearWeightTickets(formats); err != nil { res = append(res, err) } @@ -537,6 +544,23 @@ func (m *PPMShipment) validatePickupAddress(formats strfmt.Registry) error { return nil } +func (m *PPMShipment) validatePpmType(formats strfmt.Registry) error { + if swag.IsZero(m.PpmType) { // not required + return nil + } + + if err := m.PpmType.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ppmType") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ppmType") + } + return err + } + + return nil +} + func (m *PPMShipment) validateProGearWeightTickets(formats strfmt.Registry) error { if swag.IsZero(m.ProGearWeightTickets) { // not required return nil @@ -849,6 +873,10 @@ func (m *PPMShipment) ContextValidate(ctx context.Context, formats strfmt.Regist res = append(res, err) } + if err := m.contextValidatePpmType(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateProGearWeightTickets(ctx, formats); err != nil { res = append(res, err) } @@ -1027,6 +1055,24 @@ func (m *PPMShipment) contextValidatePickupAddress(ctx context.Context, formats return nil } +func (m *PPMShipment) contextValidatePpmType(ctx context.Context, formats strfmt.Registry) error { + + if swag.IsZero(m.PpmType) { // not required + return nil + } + + if err := m.PpmType.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ppmType") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ppmType") + } + return err + } + + return nil +} + func (m *PPMShipment) contextValidateProGearWeightTickets(ctx context.Context, formats strfmt.Registry) error { for i := 0; i < len(m.ProGearWeightTickets); i++ { diff --git a/pkg/gen/internalmessages/p_p_m_type.go b/pkg/gen/internalmessages/p_p_m_type.go new file mode 100644 index 00000000000..4ba102b4a09 --- /dev/null +++ b/pkg/gen/internalmessages/p_p_m_type.go @@ -0,0 +1,92 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package internalmessages + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// PPMType PPM Type +// +// # Defines a PPM type +// +// swagger:model PPMType +type PPMType string + +func NewPPMType(value PPMType) *PPMType { + return &value +} + +// Pointer returns a pointer to a freshly-allocated PPMType. +func (m PPMType) Pointer() *PPMType { + return &m +} + +const ( + + // PPMTypeINCENTIVEBASED captures enum value "INCENTIVE_BASED" + PPMTypeINCENTIVEBASED PPMType = "INCENTIVE_BASED" + + // PPMTypeACTUALEXPENSE captures enum value "ACTUAL_EXPENSE" + PPMTypeACTUALEXPENSE PPMType = "ACTUAL_EXPENSE" + + // PPMTypeSMALLPACKAGE captures enum value "SMALL_PACKAGE" + PPMTypeSMALLPACKAGE PPMType = "SMALL_PACKAGE" +) + +// for schema +var pPMTypeEnum []interface{} + +func init() { + var res []PPMType + if err := json.Unmarshal([]byte(`["INCENTIVE_BASED","ACTUAL_EXPENSE","SMALL_PACKAGE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + pPMTypeEnum = append(pPMTypeEnum, v) + } +} + +func (m PPMType) validatePPMTypeEnum(path, location string, value PPMType) error { + if err := validate.EnumCase(path, location, value, pPMTypeEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this p p m type +func (m PPMType) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validatePPMTypeEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validate this p p m type based on the context it is used +func (m PPMType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := validate.ReadOnly(ctx, "", "body", PPMType(m)); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/models/moving_expense.go b/pkg/models/moving_expense.go index 97ea06f1a38..92b4d5ab77c 100644 --- a/pkg/models/moving_expense.go +++ b/pkg/models/moving_expense.go @@ -29,6 +29,8 @@ const ( MovingExpenseReceiptTypeTolls MovingExpenseReceiptType = "TOLLS" // MovingExpenseReceiptTypeWeighingFee captures enum value "WEIGHING_FEE" MovingExpenseReceiptTypeWeighingFee MovingExpenseReceiptType = "WEIGHING_FEE" + // MovingExpenseReceiptTypeSmallPackage captures enum value "SMALL_PACKAGE" + MovingExpenseReceiptTypeSmallPackage MovingExpenseReceiptType = "SMALL_PACKAGE" // MovingExpenseReceiptTypeOther captures enum value "OTHER" MovingExpenseReceiptTypeOther MovingExpenseReceiptType = "OTHER" ) diff --git a/pkg/models/ppm_shipment.go b/pkg/models/ppm_shipment.go index d53bdb5b3ac..392a3fa9562 100644 --- a/pkg/models/ppm_shipment.go +++ b/pkg/models/ppm_shipment.go @@ -180,9 +180,22 @@ type PPMDocuments struct { ProgearWeightTickets } +// PPMType represents the type of a PPM shipment +type PPMType string + +const ( + // PPMTypeIncentiveBased captures enum value "INCENTIVE_BASED" + PPMTypeIncentiveBased PPMType = "INCENTIVE_BASED" + // PPMTypeActualExpense captures enum value "ACTUAL_EXPENSE" + PPMTypeActualExpense PPMType = "ACTUAL_EXPENSE" + // PPMTypeSmallPackage captures enum value "SMALL_PACKAGE" + PPMTypeSmallPackage PPMType = "SMALL_PACKAGE" +) + // PPMShipment is the portion of a move that a service member performs themselves type PPMShipment struct { ID uuid.UUID `json:"id" db:"id"` + PPMType PPMType `json:"ppm_type" db:"ppm_type"` ShipmentID uuid.UUID `json:"shipment_id" db:"shipment_id"` Shipment MTOShipment `belongs_to:"mto_shipments" fk_id:"shipment_id"` CreatedAt time.Time `json:"created_at" db:"created_at"` diff --git a/pkg/services/ppmshipment/ppm_shipment_creator.go b/pkg/services/ppmshipment/ppm_shipment_creator.go index 75f8e50f7ae..b76cfbe778d 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator.go @@ -56,6 +56,11 @@ func (f *ppmShipmentCreator) createPPMShipment(appCtx appcontext.AppContext, ppm return apperror.NewInvalidInputError(uuid.Nil, nil, nil, "Must have a DRAFT or SUBMITTED status associated with PPM shipment") } + // default PPM type is incentive based + if ppmShipment.PPMType == "" { + ppmShipment.PPMType = models.PPMType(models.PPMTypeIncentiveBased) + } + // create pickup and destination addresses if ppmShipment.PickupAddress != nil { address, err = f.addressCreator.CreateAddress(txnAppCtx, ppmShipment.PickupAddress) diff --git a/pkg/services/ppmshipment/ppm_shipment_creator_test.go b/pkg/services/ppmshipment/ppm_shipment_creator_test.go index 22fc576d525..73c545ca608 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator_test.go @@ -108,6 +108,7 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { suite.Nil(err) suite.NotNil(createdPPMShipment) + suite.Equal(createdPPMShipment.PPMType, models.PPMTypeIncentiveBased) suite.Equal(createdPPMShipment.Shipment.MarketCode, models.MarketCodeDomestic) }) diff --git a/src/shared/constants.js b/src/shared/constants.js index 56b7601c585..0073ee5e28f 100644 --- a/src/shared/constants.js +++ b/src/shared/constants.js @@ -102,6 +102,18 @@ export const SHIPMENT_TYPES = { UNACCOMPANIED_BAGGAGE: 'UNACCOMPANIED_BAGGAGE', }; +export const PPM_TYPES = { + INCENTIVE_BASED: 'INCENTIVE_BASED', + ACTUAL_EXPENSE: 'ACTUAL_EXPENSE', + SMALL_PACKAGE: 'SMALL_PACKAGE', +}; + +export const ppmTypeLabels = [ + { key: PPM_TYPES.INCENTIVE_BASED, label: 'Incentive-based' }, + { key: PPM_TYPES.ACTUAL_EXPENSE, label: 'Actual Expense' }, + { key: PPM_TYPES.SMALL_PACKAGE, label: 'Small Package' }, +]; + // These constants are used for forming URLs that have the shipment type in // them so that they are human readable. export const SHIPMENT_OPTIONS_URL = { @@ -203,6 +215,7 @@ export const DEFAULT_EMPTY_VALUE = '—'; // emdash export const FEATURE_FLAG_KEYS = { PPM: 'ppm', + PPM_SPR: 'ppm_spr', NTS: 'nts', NTSR: 'ntsr', BOAT: 'boat', diff --git a/swagger-def/definitions/PPMShipment.yaml b/swagger-def/definitions/PPMShipment.yaml index c75524f94eb..274ec216a0b 100644 --- a/swagger-def/definitions/PPMShipment.yaml +++ b/swagger-def/definitions/PPMShipment.yaml @@ -7,6 +7,8 @@ properties: format: uuid type: string readOnly: true + ppmType: + $ref: 'PPMType.yaml' shipmentId: description: The id of the parent MTOShipment object example: 1f2270c7-7166-40ae-981e-b200ebdf3054 diff --git a/swagger-def/definitions/PPMType.yaml b/swagger-def/definitions/PPMType.yaml new file mode 100644 index 00000000000..a87dc0c57ee --- /dev/null +++ b/swagger-def/definitions/PPMType.yaml @@ -0,0 +1,8 @@ +type: string +title: PPM Type +description: Defines a PPM type +readOnly: true +enum: + - INCENTIVE_BASED + - ACTUAL_EXPENSE + - SMALL_PACKAGE diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index e51d85a9794..b9f0c6d6e06 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -9715,6 +9715,15 @@ definitions: given SIT service items for an instance of SIT (Either Origin or Destination), grouped by the date they went into SIT and service items limited explicitly to SIT related Re Service Codes. + PPMType: + type: string + title: PPM Type + description: Defines a PPM type + readOnly: true + enum: + - INCENTIVE_BASED + - ACTUAL_EXPENSE + - SMALL_PACKAGE PPMShipmentStatus: description: | Status of the PPM Shipment: @@ -10340,6 +10349,8 @@ definitions: format: uuid type: string readOnly: true + ppmType: + $ref: '#/definitions/PPMType' shipmentId: description: The id of the parent MTOShipment object example: 1f2270c7-7166-40ae-981e-b200ebdf3054 diff --git a/swagger/internal.yaml b/swagger/internal.yaml index 2f772c2ffcc..f9ded41f350 100644 --- a/swagger/internal.yaml +++ b/swagger/internal.yaml @@ -2967,6 +2967,15 @@ definitions: - id - service_member_id - uploads + PPMType: + type: string + title: PPM Type + description: Defines a PPM type + readOnly: true + enum: + - INCENTIVE_BASED + - ACTUAL_EXPENSE + - SMALL_PACKAGE PPMShipmentStatus: description: | Status of the PPM Shipment: @@ -3598,6 +3607,8 @@ definitions: format: uuid type: string readOnly: true + ppmType: + $ref: '#/definitions/PPMType' shipmentId: description: The id of the parent MTOShipment object example: 1f2270c7-7166-40ae-981e-b200ebdf3054 From 00c290a610651ae6d30a873c872d504613713261 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 25 Feb 2025 17:43:42 +0000 Subject: [PATCH 2/3] adding some suhweet validation --- pkg/models/ppm_shipment.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/models/ppm_shipment.go b/pkg/models/ppm_shipment.go index 392a3fa9562..ecb04cc45ca 100644 --- a/pkg/models/ppm_shipment.go +++ b/pkg/models/ppm_shipment.go @@ -192,6 +192,13 @@ const ( PPMTypeSmallPackage PPMType = "SMALL_PACKAGE" ) +// AllowedPPMTypes is a list of all the allowed values for PPM types +var AllowedPPMTypes = []string{ + string(PPMTypeIncentiveBased), + string(PPMTypeActualExpense), + string(PPMTypeSmallPackage), +} + // PPMShipment is the portion of a move that a service member performs themselves type PPMShipment struct { ID uuid.UUID `json:"id" db:"id"` @@ -277,6 +284,7 @@ type PPMShipments []PPMShipment func (p PPMShipment) Validate(_ *pop.Connection) (*validate.Errors, error) { return validate.Validate( &validators.UUIDIsPresent{Name: "ShipmentID", Field: p.ShipmentID}, + &validators.StringInclusion{Name: "PPMType", Field: string(p.PPMType), List: AllowedPPMTypes}, &OptionalTimeIsPresent{Name: "DeletedAt", Field: p.DeletedAt}, &validators.TimeIsPresent{Name: "ExpectedDepartureDate", Field: p.ExpectedDepartureDate}, &validators.StringInclusion{Name: "Status", Field: string(p.Status), List: AllowedPPMShipmentStatuses}, From 3821ff9799b397d65efd6059dbfc0dc6188608d3 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Wed, 26 Feb 2025 19:10:55 +0000 Subject: [PATCH 3/3] update tests, fix storybook --- pkg/models/ppm_shipment_test.go | 3 +++ src/components/Table/TableQueue.stories.jsx | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pkg/models/ppm_shipment_test.go b/pkg/models/ppm_shipment_test.go index 7dbeb27f545..f4b2662a98b 100644 --- a/pkg/models/ppm_shipment_test.go +++ b/pkg/models/ppm_shipment_test.go @@ -29,6 +29,7 @@ func (suite *ModelSuite) TestPPMShipmentValidation() { }{ "Successful Minimal Validation": { ppmShipment: models.PPMShipment{ + PPMType: models.PPMTypeIncentiveBased, ShipmentID: uuid.Must(uuid.NewV4()), ExpectedDepartureDate: testdatagen.PeakRateCycleStart, Status: models.PPMShipmentStatusDraft, @@ -39,6 +40,7 @@ func (suite *ModelSuite) TestPPMShipmentValidation() { }, "Missing Required Fields": { ppmShipment: models.PPMShipment{ + PPMType: models.PPMTypeIncentiveBased, PickupAddressID: models.UUIDPointer(uuid.Nil), DestinationAddressID: models.UUIDPointer(uuid.Nil), }, @@ -53,6 +55,7 @@ func (suite *ModelSuite) TestPPMShipmentValidation() { "Optional fields raise errors with invalid values": { ppmShipment: models.PPMShipment{ // Setting up min required fields here so that we don't get these in our errors. + PPMType: models.PPMTypeIncentiveBased, ShipmentID: uuid.Must(uuid.NewV4()), ExpectedDepartureDate: testdatagen.PeakRateCycleStart, Status: models.PPMShipmentStatusDraft, diff --git a/src/components/Table/TableQueue.stories.jsx b/src/components/Table/TableQueue.stories.jsx index 346e67fb7dd..94d9321a75d 100644 --- a/src/components/Table/TableQueue.stories.jsx +++ b/src/components/Table/TableQueue.stories.jsx @@ -10,6 +10,7 @@ import { BRANCH_OPTIONS, MOVE_STATUS_OPTIONS } from 'constants/queues'; import SelectFilter from 'components/Table/Filters/SelectFilter'; import DateSelectFilter from 'components/Table/Filters/DateSelectFilter'; import { store } from 'shared/store'; +import { MockProviders } from 'testUtils'; export default { title: 'Office Components/Table', @@ -87,25 +88,32 @@ const defaultProps = { export const TXOTable = () => (
- + + +
); export const TXOTableSortable = () => (
- + + +
); export const TXOTableFilters = () => (
- + + +
); export const TXOTablePagination = () => (
- {' '} - + + +
);