diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index 344b9fab315..c0442e6e605 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1018,4 +1018,5 @@ 20241007184230_insertReOconusRateAreas.up.sql 20241007184259_insertReIntlTransTime.up.sql 20241007224427_update_addresses_us_post_region_cities_id.up.sql +20241008212243_populate_market_code_on_shipments_table.up.sql 20241009210749_create_view_v_locations.up.sql diff --git a/migrations/app/schema/20241008212243_populate_market_code_on_shipments_table.up.sql b/migrations/app/schema/20241008212243_populate_market_code_on_shipments_table.up.sql new file mode 100644 index 00000000000..e5dc39038f8 --- /dev/null +++ b/migrations/app/schema/20241008212243_populate_market_code_on_shipments_table.up.sql @@ -0,0 +1,18 @@ +-- Set temp timeout due to potentially large modification +-- Time is 5 minutes in milliseconds +SET statement_timeout = 300000; +SET lock_timeout = 300000; +SET idle_in_transaction_session_timeout = 300000; + +-- Populate the new market_code column for shipments +-- since we do not support OCONUS moves yet, these should all be "d" +UPDATE mto_shipments +SET market_code = 'd' +WHERE market_code IS NULL; + +-- Add a NOT NULL constraint to the market_code column after we populate with data +ALTER TABLE mto_shipments +ALTER COLUMN market_code SET NOT NULL; + +-- fixing typo from previous migration +COMMENT ON COLUMN mto_shipments.market_code IS 'Market code indicator for the shipment. i for international and d for domestic.'; \ No newline at end of file diff --git a/pkg/factory/mto_shipment_factory.go b/pkg/factory/mto_shipment_factory.go index ccd2580b484..74f45e3d937 100644 --- a/pkg/factory/mto_shipment_factory.go +++ b/pkg/factory/mto_shipment_factory.go @@ -41,6 +41,7 @@ func buildMTOShipmentWithBuildType(db *pop.Connection, customs []Customization, // defaults change depending on mtoshipment build type defaultShipmentType := models.MTOShipmentTypeHHG defaultStatus := models.MTOShipmentStatusSubmitted + defaultMarketCode := models.MarketCodeDomestic setupPickupAndDelivery := true hasStorageFacilityCustom := findValidCustomization(customs, StorageFacility) != nil buildStorageFacility := @@ -75,6 +76,7 @@ func buildMTOShipmentWithBuildType(db *pop.Connection, customs []Customization, MoveTaskOrderID: move.ID, ShipmentType: defaultShipmentType, Status: defaultStatus, + MarketCode: defaultMarketCode, } if cMtoShipment.Status == models.MTOShipmentStatusApproved { @@ -377,6 +379,11 @@ func BuildMTOShipmentMinimal(db *pop.Connection, customs []Customization, traits } } + mtoShipment.MarketCode = models.MarketCodeDomestic + if db != nil { + mustSave(db, &mtoShipment) + } + return mtoShipment } diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 35351062b1b..1ca787f601e 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -9199,6 +9199,15 @@ func init() { "format": "uuid", "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "mobileHomeShipment": { "$ref": "#/definitions/MobileHome" }, @@ -24887,6 +24896,15 @@ func init() { "format": "uuid", "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "mobileHomeShipment": { "$ref": "#/definitions/MobileHome" }, diff --git a/pkg/gen/ghcmessages/m_t_o_shipment.go b/pkg/gen/ghcmessages/m_t_o_shipment.go index 7ddc7e40b03..ca5097209b4 100644 --- a/pkg/gen/ghcmessages/m_t_o_shipment.go +++ b/pkg/gen/ghcmessages/m_t_o_shipment.go @@ -7,6 +7,7 @@ package ghcmessages import ( "context" + "encoding/json" "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" @@ -120,6 +121,11 @@ type MTOShipment struct { // Format: uuid ID strfmt.UUID `json:"id,omitempty"` + // Single-letter designator for domestic (d) or international (i) shipments + // Example: d + // Enum: [d i] + MarketCode string `json:"marketCode,omitempty"` + // mobile home shipment MobileHomeShipment *MobileHome `json:"mobileHomeShipment,omitempty"` @@ -284,6 +290,10 @@ func (m *MTOShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateMarketCode(formats); err != nil { + res = append(res, err) + } + if err := m.validateMobileHomeShipment(formats); err != nil { res = append(res, err) } @@ -550,6 +560,48 @@ func (m *MTOShipment) validateID(formats strfmt.Registry) error { return nil } +var mTOShipmentTypeMarketCodePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["d","i"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + mTOShipmentTypeMarketCodePropEnum = append(mTOShipmentTypeMarketCodePropEnum, v) + } +} + +const ( + + // MTOShipmentMarketCodeD captures enum value "d" + MTOShipmentMarketCodeD string = "d" + + // MTOShipmentMarketCodeI captures enum value "i" + MTOShipmentMarketCodeI string = "i" +) + +// prop value enum +func (m *MTOShipment) validateMarketCodeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, mTOShipmentTypeMarketCodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *MTOShipment) validateMarketCode(formats strfmt.Registry) error { + if swag.IsZero(m.MarketCode) { // not required + return nil + } + + // value enum + if err := m.validateMarketCodeEnum("marketCode", "body", m.MarketCode); err != nil { + return err + } + + return nil +} + func (m *MTOShipment) validateMobileHomeShipment(formats strfmt.Registry) error { if swag.IsZero(m.MobileHomeShipment) { // not required return nil diff --git a/pkg/gen/internalapi/embedded_spec.go b/pkg/gen/internalapi/embedded_spec.go index a72caaeec33..641785e07f3 100644 --- a/pkg/gen/internalapi/embedded_spec.go +++ b/pkg/gen/internalapi/embedded_spec.go @@ -4774,6 +4774,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "mobileHomeShipment": { "$ref": "#/definitions/MobileHome" }, @@ -13407,6 +13416,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "mobileHomeShipment": { "$ref": "#/definitions/MobileHome" }, diff --git a/pkg/gen/internalmessages/m_t_o_shipment.go b/pkg/gen/internalmessages/m_t_o_shipment.go index c77146cee30..8e4499f969d 100644 --- a/pkg/gen/internalmessages/m_t_o_shipment.go +++ b/pkg/gen/internalmessages/m_t_o_shipment.go @@ -7,6 +7,7 @@ package internalmessages import ( "context" + "encoding/json" "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" @@ -65,6 +66,11 @@ type MTOShipment struct { // Format: uuid ID strfmt.UUID `json:"id,omitempty"` + // Single-letter designator for domestic (d) or international (i) shipments + // Example: d + // Enum: [d i] + MarketCode string `json:"marketCode,omitempty"` + // mobile home shipment MobileHomeShipment *MobileHome `json:"mobileHomeShipment,omitempty"` @@ -143,6 +149,10 @@ func (m *MTOShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateMarketCode(formats); err != nil { + res = append(res, err) + } + if err := m.validateMobileHomeShipment(formats); err != nil { res = append(res, err) } @@ -280,6 +290,48 @@ func (m *MTOShipment) validateID(formats strfmt.Registry) error { return nil } +var mTOShipmentTypeMarketCodePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["d","i"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + mTOShipmentTypeMarketCodePropEnum = append(mTOShipmentTypeMarketCodePropEnum, v) + } +} + +const ( + + // MTOShipmentMarketCodeD captures enum value "d" + MTOShipmentMarketCodeD string = "d" + + // MTOShipmentMarketCodeI captures enum value "i" + MTOShipmentMarketCodeI string = "i" +) + +// prop value enum +func (m *MTOShipment) validateMarketCodeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, mTOShipmentTypeMarketCodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *MTOShipment) validateMarketCode(formats strfmt.Registry) error { + if swag.IsZero(m.MarketCode) { // not required + return nil + } + + // value enum + if err := m.validateMarketCodeEnum("marketCode", "body", m.MarketCode); err != nil { + return err + } + + return nil +} + func (m *MTOShipment) validateMobileHomeShipment(formats strfmt.Registry) error { if swag.IsZero(m.MobileHomeShipment) { // not required return nil diff --git a/pkg/gen/primeapi/embedded_spec.go b/pkg/gen/primeapi/embedded_spec.go index 53b0967c06d..81f1c95c22f 100644 --- a/pkg/gen/primeapi/embedded_spec.go +++ b/pkg/gen/primeapi/embedded_spec.go @@ -2539,6 +2539,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "moveTaskOrderID": { "description": "The ID of the move for this shipment.", "type": "string", @@ -7252,6 +7261,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "moveTaskOrderID": { "description": "The ID of the move for this shipment.", "type": "string", diff --git a/pkg/gen/primemessages/m_t_o_shipment_without_service_items.go b/pkg/gen/primemessages/m_t_o_shipment_without_service_items.go index e8c513313ec..f3cbfc05c16 100644 --- a/pkg/gen/primemessages/m_t_o_shipment_without_service_items.go +++ b/pkg/gen/primemessages/m_t_o_shipment_without_service_items.go @@ -117,6 +117,11 @@ type MTOShipmentWithoutServiceItems struct { // Format: uuid ID strfmt.UUID `json:"id,omitempty"` + // Single-letter designator for domestic (d) or international (i) shipments + // Example: d + // Enum: [d i] + MarketCode string `json:"marketCode,omitempty"` + // The ID of the move for this shipment. // Example: 1f2270c7-7166-40ae-981e-b200ebdf3054 // Read Only: true @@ -267,6 +272,10 @@ func (m *MTOShipmentWithoutServiceItems) Validate(formats strfmt.Registry) error res = append(res, err) } + if err := m.validateMarketCode(formats); err != nil { + res = append(res, err) + } + if err := m.validateMoveTaskOrderID(formats); err != nil { res = append(res, err) } @@ -500,6 +509,48 @@ func (m *MTOShipmentWithoutServiceItems) validateID(formats strfmt.Registry) err return nil } +var mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["d","i"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum = append(mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum, v) + } +} + +const ( + + // MTOShipmentWithoutServiceItemsMarketCodeD captures enum value "d" + MTOShipmentWithoutServiceItemsMarketCodeD string = "d" + + // MTOShipmentWithoutServiceItemsMarketCodeI captures enum value "i" + MTOShipmentWithoutServiceItemsMarketCodeI string = "i" +) + +// prop value enum +func (m *MTOShipmentWithoutServiceItems) validateMarketCodeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *MTOShipmentWithoutServiceItems) validateMarketCode(formats strfmt.Registry) error { + if swag.IsZero(m.MarketCode) { // not required + return nil + } + + // value enum + if err := m.validateMarketCodeEnum("marketCode", "body", m.MarketCode); err != nil { + return err + } + + return nil +} + func (m *MTOShipmentWithoutServiceItems) validateMoveTaskOrderID(formats strfmt.Registry) error { if swag.IsZero(m.MoveTaskOrderID) { // not required return nil diff --git a/pkg/gen/primev2api/embedded_spec.go b/pkg/gen/primev2api/embedded_spec.go index 2857267df7d..1367c101cdd 100644 --- a/pkg/gen/primev2api/embedded_spec.go +++ b/pkg/gen/primev2api/embedded_spec.go @@ -1664,6 +1664,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "moveTaskOrderID": { "description": "The ID of the move for this shipment.", "type": "string", @@ -5138,6 +5147,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "moveTaskOrderID": { "description": "The ID of the move for this shipment.", "type": "string", diff --git a/pkg/gen/primev2messages/m_t_o_shipment_without_service_items.go b/pkg/gen/primev2messages/m_t_o_shipment_without_service_items.go index ec8598c2d6b..61ca96b1fe5 100644 --- a/pkg/gen/primev2messages/m_t_o_shipment_without_service_items.go +++ b/pkg/gen/primev2messages/m_t_o_shipment_without_service_items.go @@ -117,6 +117,11 @@ type MTOShipmentWithoutServiceItems struct { // Format: uuid ID strfmt.UUID `json:"id,omitempty"` + // Single-letter designator for domestic (d) or international (i) shipments + // Example: d + // Enum: [d i] + MarketCode string `json:"marketCode,omitempty"` + // The ID of the move for this shipment. // Example: 1f2270c7-7166-40ae-981e-b200ebdf3054 // Read Only: true @@ -267,6 +272,10 @@ func (m *MTOShipmentWithoutServiceItems) Validate(formats strfmt.Registry) error res = append(res, err) } + if err := m.validateMarketCode(formats); err != nil { + res = append(res, err) + } + if err := m.validateMoveTaskOrderID(formats); err != nil { res = append(res, err) } @@ -500,6 +509,48 @@ func (m *MTOShipmentWithoutServiceItems) validateID(formats strfmt.Registry) err return nil } +var mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["d","i"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum = append(mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum, v) + } +} + +const ( + + // MTOShipmentWithoutServiceItemsMarketCodeD captures enum value "d" + MTOShipmentWithoutServiceItemsMarketCodeD string = "d" + + // MTOShipmentWithoutServiceItemsMarketCodeI captures enum value "i" + MTOShipmentWithoutServiceItemsMarketCodeI string = "i" +) + +// prop value enum +func (m *MTOShipmentWithoutServiceItems) validateMarketCodeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *MTOShipmentWithoutServiceItems) validateMarketCode(formats strfmt.Registry) error { + if swag.IsZero(m.MarketCode) { // not required + return nil + } + + // value enum + if err := m.validateMarketCodeEnum("marketCode", "body", m.MarketCode); err != nil { + return err + } + + return nil +} + func (m *MTOShipmentWithoutServiceItems) validateMoveTaskOrderID(formats strfmt.Registry) error { if swag.IsZero(m.MoveTaskOrderID) { // not required return nil diff --git a/pkg/gen/primev3api/embedded_spec.go b/pkg/gen/primev3api/embedded_spec.go index 2dcc1067b4e..29ea00c2913 100644 --- a/pkg/gen/primev3api/embedded_spec.go +++ b/pkg/gen/primev3api/embedded_spec.go @@ -1835,6 +1835,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "mobileHomeShipment": { "$ref": "#/definitions/MobileHome" }, @@ -5663,6 +5672,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "mobileHomeShipment": { "$ref": "#/definitions/MobileHome" }, diff --git a/pkg/gen/primev3messages/m_t_o_shipment_without_service_items.go b/pkg/gen/primev3messages/m_t_o_shipment_without_service_items.go index af62c27c498..72d878b9b30 100644 --- a/pkg/gen/primev3messages/m_t_o_shipment_without_service_items.go +++ b/pkg/gen/primev3messages/m_t_o_shipment_without_service_items.go @@ -120,6 +120,11 @@ type MTOShipmentWithoutServiceItems struct { // Format: uuid ID strfmt.UUID `json:"id,omitempty"` + // Single-letter designator for domestic (d) or international (i) shipments + // Example: d + // Enum: [d i] + MarketCode string `json:"marketCode,omitempty"` + // mobile home shipment MobileHomeShipment *MobileHome `json:"mobileHomeShipment,omitempty"` @@ -279,6 +284,10 @@ func (m *MTOShipmentWithoutServiceItems) Validate(formats strfmt.Registry) error res = append(res, err) } + if err := m.validateMarketCode(formats); err != nil { + res = append(res, err) + } + if err := m.validateMobileHomeShipment(formats); err != nil { res = append(res, err) } @@ -543,6 +552,48 @@ func (m *MTOShipmentWithoutServiceItems) validateID(formats strfmt.Registry) err return nil } +var mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["d","i"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum = append(mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum, v) + } +} + +const ( + + // MTOShipmentWithoutServiceItemsMarketCodeD captures enum value "d" + MTOShipmentWithoutServiceItemsMarketCodeD string = "d" + + // MTOShipmentWithoutServiceItemsMarketCodeI captures enum value "i" + MTOShipmentWithoutServiceItemsMarketCodeI string = "i" +) + +// prop value enum +func (m *MTOShipmentWithoutServiceItems) validateMarketCodeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, mTOShipmentWithoutServiceItemsTypeMarketCodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *MTOShipmentWithoutServiceItems) validateMarketCode(formats strfmt.Registry) error { + if swag.IsZero(m.MarketCode) { // not required + return nil + } + + // value enum + if err := m.validateMarketCodeEnum("marketCode", "body", m.MarketCode); err != nil { + return err + } + + return nil +} + func (m *MTOShipmentWithoutServiceItems) validateMobileHomeShipment(formats strfmt.Registry) error { if swag.IsZero(m.MobileHomeShipment) { // not required return nil diff --git a/pkg/gen/supportapi/embedded_spec.go b/pkg/gen/supportapi/embedded_spec.go index a824a885032..ded60674b1f 100644 --- a/pkg/gen/supportapi/embedded_spec.go +++ b/pkg/gen/supportapi/embedded_spec.go @@ -1685,6 +1685,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "moveTaskOrderID": { "type": "string", "format": "uuid", @@ -4531,6 +4540,15 @@ func init() { "readOnly": true, "example": "1f2270c7-7166-40ae-981e-b200ebdf3054" }, + "marketCode": { + "description": "Single-letter designator for domestic (d) or international (i) shipments", + "type": "string", + "enum": [ + "d", + "i" + ], + "example": "d" + }, "moveTaskOrderID": { "type": "string", "format": "uuid", diff --git a/pkg/gen/supportmessages/m_t_o_shipment.go b/pkg/gen/supportmessages/m_t_o_shipment.go index f3f570351f0..440d337a40a 100644 --- a/pkg/gen/supportmessages/m_t_o_shipment.go +++ b/pkg/gen/supportmessages/m_t_o_shipment.go @@ -66,6 +66,11 @@ type MTOShipment struct { // Format: uuid ID strfmt.UUID `json:"id,omitempty"` + // Single-letter designator for domestic (d) or international (i) shipments + // Example: d + // Enum: [d i] + MarketCode string `json:"marketCode,omitempty"` + // move task order ID // Example: 1f2270c7-7166-40ae-981e-b200ebdf3054 // Read Only: true @@ -171,6 +176,8 @@ func (m *MTOShipment) UnmarshalJSON(raw []byte) error { ID strfmt.UUID `json:"id,omitempty"` + MarketCode string `json:"marketCode,omitempty"` + MoveTaskOrderID strfmt.UUID `json:"moveTaskOrderID,omitempty"` MtoServiceItems json.RawMessage `json:"mtoServiceItems"` @@ -256,6 +263,9 @@ func (m *MTOShipment) UnmarshalJSON(raw []byte) error { // id result.ID = data.ID + // marketCode + result.MarketCode = data.MarketCode + // moveTaskOrderID result.MoveTaskOrderID = data.MoveTaskOrderID @@ -340,6 +350,8 @@ func (m MTOShipment) MarshalJSON() ([]byte, error) { ID strfmt.UUID `json:"id,omitempty"` + MarketCode string `json:"marketCode,omitempty"` + MoveTaskOrderID strfmt.UUID `json:"moveTaskOrderID,omitempty"` PickupAddress *Address `json:"pickupAddress,omitempty"` @@ -395,6 +407,8 @@ func (m MTOShipment) MarshalJSON() ([]byte, error) { ID: m.ID, + MarketCode: m.MarketCode, + MoveTaskOrderID: m.MoveTaskOrderID, PickupAddress: m.PickupAddress, @@ -477,6 +491,10 @@ func (m *MTOShipment) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateMarketCode(formats); err != nil { + res = append(res, err) + } + if err := m.validateMoveTaskOrderID(formats); err != nil { res = append(res, err) } @@ -635,6 +653,48 @@ func (m *MTOShipment) validateID(formats strfmt.Registry) error { return nil } +var mTOShipmentTypeMarketCodePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["d","i"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + mTOShipmentTypeMarketCodePropEnum = append(mTOShipmentTypeMarketCodePropEnum, v) + } +} + +const ( + + // MTOShipmentMarketCodeD captures enum value "d" + MTOShipmentMarketCodeD string = "d" + + // MTOShipmentMarketCodeI captures enum value "i" + MTOShipmentMarketCodeI string = "i" +) + +// prop value enum +func (m *MTOShipment) validateMarketCodeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, mTOShipmentTypeMarketCodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *MTOShipment) validateMarketCode(formats strfmt.Registry) error { + if swag.IsZero(m.MarketCode) { // not required + return nil + } + + // value enum + if err := m.validateMarketCodeEnum("marketCode", "body", m.MarketCode); err != nil { + return err + } + + return nil +} + func (m *MTOShipment) validateMoveTaskOrderID(formats strfmt.Registry) error { if swag.IsZero(m.MoveTaskOrderID) { // not required return nil diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go index 61d2e51d3c0..738b9802a50 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go @@ -1371,6 +1371,14 @@ func LineOfAccounting(lineOfAccounting *models.LineOfAccounting) *ghcmessages.Li } } +// MarketCode payload +func MarketCode(marketCode *models.MarketCode) string { + if marketCode == nil { + return "" // Or a default string value + } + return string(*marketCode) +} + // MTOShipment payload func MTOShipment(storer storage.FileStorer, mtoShipment *models.MTOShipment, sitStatusPayload *ghcmessages.SITStatus) *ghcmessages.MTOShipment { @@ -1419,6 +1427,7 @@ func MTOShipment(storer storage.FileStorer, mtoShipment *models.MTOShipment, sit MobileHomeShipment: MobileHomeShipment(storer, mtoShipment.MobileHome), DeliveryAddressUpdate: ShipmentAddressUpdate(mtoShipment.DeliveryAddressUpdate), ShipmentLocator: handlers.FmtStringPtr(mtoShipment.ShipmentLocator), + MarketCode: MarketCode(&mtoShipment.MarketCode), } if mtoShipment.Distance != nil { diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go index 34dc9c5b2db..e39e8cb74f3 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go @@ -368,3 +368,25 @@ func (suite *PayloadsSuite) TestSearchMoves() { suite.NotNil(payload) }) } + +func (suite *PayloadsSuite) TestMarketCode() { + suite.Run("returns nil when marketCode is nil", func() { + var marketCode *models.MarketCode = nil + result := MarketCode(marketCode) + suite.Equal(result, "") + }) + + suite.Run("returns string when marketCode is not nil", func() { + marketCodeDomestic := models.MarketCodeDomestic + result := MarketCode(&marketCodeDomestic) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("d", result, "Expected result to be 'd' for domestic market code") + }) + + suite.Run("returns string when marketCode is international", func() { + marketCodeInternational := models.MarketCodeInternational + result := MarketCode(&marketCodeInternational) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("i", result, "Expected result to be 'i' for international market code") + }) +} diff --git a/pkg/handlers/internalapi/internal/payloads/model_to_payload.go b/pkg/handlers/internalapi/internal/payloads/model_to_payload.go index 92abb7b948d..fd404ebb02f 100644 --- a/pkg/handlers/internalapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/internalapi/internal/payloads/model_to_payload.go @@ -180,6 +180,14 @@ func MobileHomeShipment(storer storage.FileStorer, mobileHomeShipment *models.Mo return payloadMobileHomeShipment } +// MarketCode payload +func MarketCode(marketCode *models.MarketCode) string { + if marketCode == nil { + return "" // Or a default string value + } + return string(*marketCode) +} + // MTOShipment payload func MTOShipment(storer storage.FileStorer, mtoShipment *models.MTOShipment) *internalmessages.MTOShipment { payload := &internalmessages.MTOShipment{ @@ -208,6 +216,7 @@ func MTOShipment(storer storage.FileStorer, mtoShipment *models.MTOShipment) *in MobileHomeShipment: MobileHomeShipment(storer, mtoShipment.MobileHome), ETag: etag.GenerateEtag(mtoShipment.UpdatedAt), ShipmentLocator: handlers.FmtStringPtr(mtoShipment.ShipmentLocator), + MarketCode: MarketCode(&mtoShipment.MarketCode), } if mtoShipment.HasSecondaryPickupAddress != nil && !*mtoShipment.HasSecondaryPickupAddress { payload.SecondaryPickupAddress = nil diff --git a/pkg/handlers/internalapi/internal/payloads/model_to_payload_test.go b/pkg/handlers/internalapi/internal/payloads/model_to_payload_test.go new file mode 100644 index 00000000000..d7857c2872d --- /dev/null +++ b/pkg/handlers/internalapi/internal/payloads/model_to_payload_test.go @@ -0,0 +1,27 @@ +package payloads + +import ( + "github.com/transcom/mymove/pkg/models" +) + +func (suite *PayloadsSuite) TestMarketCode() { + suite.Run("returns nil when marketCode is nil", func() { + var marketCode *models.MarketCode = nil + result := MarketCode(marketCode) + suite.Equal(result, "") + }) + + suite.Run("returns string when marketCode is not nil", func() { + marketCodeDomestic := models.MarketCodeDomestic + result := MarketCode(&marketCodeDomestic) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("d", result, "Expected result to be 'd' for domestic market code") + }) + + suite.Run("returns string when marketCode is international", func() { + marketCodeInternational := models.MarketCodeInternational + result := MarketCode(&marketCodeInternational) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("i", result, "Expected result to be 'i' for international market code") + }) +} diff --git a/pkg/handlers/internalapi/internal/payloads/payloads_test.go b/pkg/handlers/internalapi/internal/payloads/payloads_test.go new file mode 100644 index 00000000000..c17b8a85256 --- /dev/null +++ b/pkg/handlers/internalapi/internal/payloads/payloads_test.go @@ -0,0 +1,31 @@ +package payloads + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/transcom/mymove/pkg/handlers" + "github.com/transcom/mymove/pkg/notifications" + "github.com/transcom/mymove/pkg/storage" + storageTest "github.com/transcom/mymove/pkg/storage/test" + "github.com/transcom/mymove/pkg/testingsuite" +) + +// HandlerSuite is an abstraction of our original suite +type PayloadsSuite struct { + handlers.BaseHandlerTestSuite + storer storage.FileStorer +} + +// TestHandlerSuite creates our test suite +func TestHandlerSuite(t *testing.T) { + hs := &PayloadsSuite{ + BaseHandlerTestSuite: handlers.NewBaseHandlerTestSuite(notifications.NewStubNotificationSender("milmovelocal"), testingsuite.CurrentPackage(), + testingsuite.WithPerTestTransaction()), + storer: storageTest.NewFakeS3Storage(true), + } + + suite.Run(t, hs) + hs.PopTestSuite.TearDown() +} diff --git a/pkg/handlers/primeapi/payloads/model_to_payload.go b/pkg/handlers/primeapi/payloads/model_to_payload.go index ff1011ec119..b22666f7599 100644 --- a/pkg/handlers/primeapi/payloads/model_to_payload.go +++ b/pkg/handlers/primeapi/payloads/model_to_payload.go @@ -508,6 +508,14 @@ func PPMShipment(ppmShipment *models.PPMShipment) *primemessages.PPMShipment { return payloadPPMShipment } +// MarketCode payload +func MarketCode(marketCode *models.MarketCode) string { + if marketCode == nil { + return "" // Or a default string value + } + return string(*marketCode) +} + func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primemessages.MTOShipmentWithoutServiceItems { payload := &primemessages.MTOShipmentWithoutServiceItems{ ID: strfmt.UUID(mtoShipment.ID.String()), @@ -538,6 +546,7 @@ func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primemessa ETag: etag.GenerateEtag(mtoShipment.UpdatedAt), OriginSitAuthEndDate: (*strfmt.Date)(mtoShipment.OriginSITAuthEndDate), DestinationSitAuthEndDate: (*strfmt.Date)(mtoShipment.DestinationSITAuthEndDate), + MarketCode: MarketCode(&mtoShipment.MarketCode), } // Set up address payloads diff --git a/pkg/handlers/primeapi/payloads/model_to_payload_test.go b/pkg/handlers/primeapi/payloads/model_to_payload_test.go index e6975856623..f85c2a0ef31 100644 --- a/pkg/handlers/primeapi/payloads/model_to_payload_test.go +++ b/pkg/handlers/primeapi/payloads/model_to_payload_test.go @@ -732,3 +732,25 @@ func (suite *PayloadsSuite) TestStorageFacility() { result := StorageFacility(storage) suite.NotNil(result) } + +func (suite *PayloadsSuite) TestMarketCode() { + suite.Run("returns nil when marketCode is nil", func() { + var marketCode *models.MarketCode = nil + result := MarketCode(marketCode) + suite.Equal(result, "") + }) + + suite.Run("returns string when marketCode is not nil", func() { + marketCodeDomestic := models.MarketCodeDomestic + result := MarketCode(&marketCodeDomestic) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("d", result, "Expected result to be 'd' for domestic market code") + }) + + suite.Run("returns string when marketCode is international", func() { + marketCodeInternational := models.MarketCodeInternational + result := MarketCode(&marketCodeInternational) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("i", result, "Expected result to be 'i' for international market code") + }) +} diff --git a/pkg/handlers/primeapiv2/payloads/model_to_payload.go b/pkg/handlers/primeapiv2/payloads/model_to_payload.go index 2a2793836fd..f23fee1ecec 100644 --- a/pkg/handlers/primeapiv2/payloads/model_to_payload.go +++ b/pkg/handlers/primeapiv2/payloads/model_to_payload.go @@ -452,6 +452,14 @@ func PPMShipment(ppmShipment *models.PPMShipment) *primev2messages.PPMShipment { return payloadPPMShipment } +// MarketCode payload +func MarketCode(marketCode *models.MarketCode) string { + if marketCode == nil { + return "" // Or a default string value + } + return string(*marketCode) +} + func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primev2messages.MTOShipmentWithoutServiceItems { payload := &primev2messages.MTOShipmentWithoutServiceItems{ ID: strfmt.UUID(mtoShipment.ID.String()), @@ -484,6 +492,7 @@ func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primev2mes ETag: etag.GenerateEtag(mtoShipment.UpdatedAt), OriginSitAuthEndDate: (*strfmt.Date)(mtoShipment.OriginSITAuthEndDate), DestinationSitAuthEndDate: (*strfmt.Date)(mtoShipment.DestinationSITAuthEndDate), + MarketCode: MarketCode(&mtoShipment.MarketCode), } // Set up address payloads diff --git a/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go b/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go index c622313a84f..9cc377d77ac 100644 --- a/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go +++ b/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go @@ -785,3 +785,25 @@ func (suite *PayloadsSuite) TestStorageFacility() { result := StorageFacility(storage) suite.NotNil(result) } + +func (suite *PayloadsSuite) TestMarketCode() { + suite.Run("returns nil when marketCode is nil", func() { + var marketCode *models.MarketCode = nil + result := MarketCode(marketCode) + suite.Equal(result, "") + }) + + suite.Run("returns string when marketCode is not nil", func() { + marketCodeDomestic := models.MarketCodeDomestic + result := MarketCode(&marketCodeDomestic) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("d", result, "Expected result to be 'd' for domestic market code") + }) + + suite.Run("returns string when marketCode is international", func() { + marketCodeInternational := models.MarketCodeInternational + result := MarketCode(&marketCodeInternational) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("i", result, "Expected result to be 'i' for international market code") + }) +} diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload.go b/pkg/handlers/primeapiv3/payloads/model_to_payload.go index ab32cf1fa8b..aa6001ac9b5 100644 --- a/pkg/handlers/primeapiv3/payloads/model_to_payload.go +++ b/pkg/handlers/primeapiv3/payloads/model_to_payload.go @@ -517,6 +517,14 @@ func MobileHomeShipment(mobileHomeShipment *models.MobileHome) *primev3messages. return payloadMobileHomeShipment } +// MarketCode payload +func MarketCode(marketCode *models.MarketCode) string { + if marketCode == nil { + return "" // Or a default string value + } + return string(*marketCode) +} + func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primev3messages.MTOShipmentWithoutServiceItems { payload := &primev3messages.MTOShipmentWithoutServiceItems{ ID: strfmt.UUID(mtoShipment.ID.String()), @@ -555,6 +563,7 @@ func MTOShipmentWithoutServiceItems(mtoShipment *models.MTOShipment) *primev3mes SecondaryPickupAddress: Address(mtoShipment.SecondaryPickupAddress), TertiaryDeliveryAddress: Address(mtoShipment.TertiaryDeliveryAddress), TertiaryPickupAddress: Address(mtoShipment.TertiaryPickupAddress), + MarketCode: MarketCode(&mtoShipment.MarketCode), } // Set up address payloads diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go b/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go index b888d785c81..78a4148be38 100644 --- a/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go +++ b/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go @@ -829,3 +829,25 @@ func (suite *PayloadsSuite) TestBoatShipment() { result := BoatShipment(boatShipment) suite.NotNil(result) } + +func (suite *PayloadsSuite) TestMarketCode() { + suite.Run("returns nil when marketCode is nil", func() { + var marketCode *models.MarketCode = nil + result := MarketCode(marketCode) + suite.Equal(result, "") + }) + + suite.Run("returns string when marketCode is not nil", func() { + marketCodeDomestic := models.MarketCodeDomestic + result := MarketCode(&marketCodeDomestic) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("d", result, "Expected result to be 'd' for domestic market code") + }) + + suite.Run("returns string when marketCode is international", func() { + marketCodeInternational := models.MarketCodeInternational + result := MarketCode(&marketCodeInternational) + suite.NotNil(result, "Expected result to not be nil when marketCode is not nil") + suite.Equal("i", result, "Expected result to be 'i' for international market code") + }) +} diff --git a/pkg/models/mto_shipments.go b/pkg/models/mto_shipments.go index ed861585e93..19ce08bdf5e 100644 --- a/pkg/models/mto_shipments.go +++ b/pkg/models/mto_shipments.go @@ -166,7 +166,7 @@ type MTOShipment struct { OriginSITAuthEndDate *time.Time `db:"origin_sit_auth_end_date"` DestinationSITAuthEndDate *time.Time `db:"dest_sit_auth_end_date"` MobileHome *MobileHome `has_one:"mobile_home" fk_id:"shipment_id"` - MarketCode *MarketCode `db:"market_code"` + MarketCode MarketCode `db:"market_code"` } // TableName overrides the table name used by Pop. @@ -246,12 +246,15 @@ func (m *MTOShipment) Validate(_ *pop.Connection) (*validate.Errors, error) { string(DestinationTypeOtherThanAuthorized), }}) - // Validate MarketCode if exists - if m.MarketCode != nil { - vs = append(vs, &validators.StringInclusion{Field: string(*m.MarketCode), Name: "MarketCode", List: []string{ - string(MarketCodeDomestic), - string(MarketCodeInternational), - }}) + if m.MarketCode != "" { + vs = append(vs, &validators.StringInclusion{ + Field: string(m.MarketCode), + Name: "MarketCode", + List: []string{ + string(MarketCodeDomestic), + string(MarketCodeInternational), + }, + }) } return validate.Validate(vs...), nil diff --git a/pkg/models/mto_shipments_test.go b/pkg/models/mto_shipments_test.go index b17797726a3..8d279fbdd38 100644 --- a/pkg/models/mto_shipments_test.go +++ b/pkg/models/mto_shipments_test.go @@ -24,7 +24,7 @@ func (suite *ModelSuite) TestMTOShipmentValidation() { SITDaysAllowance: &sitDaysAllowance, TACType: &tacType, SACType: &sacType, - MarketCode: &marketCode, + MarketCode: marketCode, } expErrors := map[string][]string{} suite.verifyValidationErrors(&validMTOShipment, expErrors) @@ -45,7 +45,7 @@ func (suite *ModelSuite) TestMTOShipmentValidation() { rejectedMTOShipment := models.MTOShipment{ MoveTaskOrderID: uuid.Must(uuid.NewV4()), Status: models.MTOShipmentStatusRejected, - MarketCode: &marketCode, + MarketCode: marketCode, RejectionReason: &rejectionReason, } expErrors := map[string][]string{} @@ -74,7 +74,7 @@ func (suite *ModelSuite) TestMTOShipmentValidation() { StorageFacilityID: &uuid.Nil, TACType: &tacType, SACType: &tacType, - MarketCode: &marketCode, + MarketCode: marketCode, } expErrors := map[string][]string{ "prime_estimated_weight": {"-1000 is not greater than 0."}, diff --git a/pkg/services/address/address_creator_test.go b/pkg/services/address/address_creator_test.go index 00f9258781b..b6a303329dd 100644 --- a/pkg/services/address/address_creator_test.go +++ b/pkg/services/address/address_creator_test.go @@ -14,7 +14,7 @@ func (suite *AddressSuite) TestAddressCreator() { postalCode := "42701" oConusState := "AK" - suite.Run("Successfully creates an address", func() { + suite.Run("Successfully creates a CONUS address", func() { addressCreator := NewAddressCreator() address, err := addressCreator.CreateAddress(suite.AppContextForTest(), &models.Address{ StreetAddress1: streetAddress1, @@ -30,6 +30,7 @@ func (suite *AddressSuite) TestAddressCreator() { suite.Equal(city, address.City) suite.Equal(state, address.State) suite.Equal(postalCode, address.PostalCode) + suite.False(*address.IsOconus) suite.Nil(address.StreetAddress2) suite.NotNil(address.Country) }) diff --git a/pkg/services/mto_shipment/mto_shipment_creator.go b/pkg/services/mto_shipment/mto_shipment_creator.go index f4a63350f14..c04db364399 100644 --- a/pkg/services/mto_shipment/mto_shipment_creator.go +++ b/pkg/services/mto_shipment/mto_shipment_creator.go @@ -305,10 +305,12 @@ func (f mtoShipmentCreator) CreateMTOShipment(appCtx appcontext.AppContext, ship // For NTS-Release set the pick up address to the storage facility if shipment.ShipmentType == models.MTOShipmentTypeHHGOutOfNTSDom { shipment.PickupAddressID = &shipment.StorageFacility.AddressID + shipment.PickupAddress = &shipment.StorageFacility.Address } // For NTS set the destination address to the storage facility if shipment.ShipmentType == models.MTOShipmentTypeHHGIntoNTSDom { shipment.DestinationAddressID = &shipment.StorageFacility.AddressID + shipment.DestinationAddress = &shipment.StorageFacility.Address } } @@ -322,6 +324,24 @@ func (f mtoShipmentCreator) CreateMTOShipment(appCtx appcontext.AppContext, ship defaultSITDays := int(models.DefaultServiceMemberSITDaysAllowance) shipment.SITDaysAllowance = &defaultSITDays + // when populating the market_code column, it is considered domestic if both pickup & dest are CONUS addresses + if shipment.PickupAddress != nil && shipment.DestinationAddress != nil && + shipment.PickupAddress.IsOconus != nil && shipment.DestinationAddress.IsOconus != nil { + pickupAddress := shipment.PickupAddress + destAddress := shipment.DestinationAddress + if !*pickupAddress.IsOconus && !*destAddress.IsOconus { + marketCodeDomestic := models.MarketCodeDomestic + shipment.MarketCode = marketCodeDomestic + } else { + marketCodeInternational := models.MarketCodeInternational + shipment.MarketCode = marketCodeInternational + } + } else { + // if the conditions aren't met then it is a PPM and this logic will be changed after PPM creation + // market code can't be null so we will set it here + shipment.MarketCode = models.MarketCodeDomestic + } + // create a shipment verrs, err = f.builder.CreateOne(txnAppCtx, shipment) diff --git a/pkg/services/mto_shipment/mto_shipment_creator_test.go b/pkg/services/mto_shipment/mto_shipment_creator_test.go index 9c8fb052b38..4ada4a31e55 100644 --- a/pkg/services/mto_shipment/mto_shipment_creator_test.go +++ b/pkg/services/mto_shipment/mto_shipment_creator_test.go @@ -150,7 +150,7 @@ func (suite *MTOShipmentServiceSuite) TestCreateMTOShipment() { }) // Happy path - suite.Run("If the shipment is created successfully it should be returned", func() { + suite.Run("If a domestic shipment is created successfully it should be returned", func() { subtestData := suite.createSubtestData(nil) creator := subtestData.shipmentCreator @@ -171,6 +171,49 @@ func (suite *MTOShipmentServiceSuite) TestCreateMTOShipment() { suite.Equal(models.MTOShipmentStatusDraft, createdShipment.Status) suite.NotEmpty(createdShipment.PickupAddressID) suite.NotEmpty(createdShipment.DestinationAddressID) + // both pickup and destination addresses should be CONUS + suite.False(*createdShipment.PickupAddress.IsOconus) + suite.False(*createdShipment.DestinationAddress.IsOconus) + suite.Equal(createdShipment.MarketCode, models.MarketCodeDomestic) + }) + + suite.Run("If an international shipment is created successfully it should be returned", func() { + subtestData := suite.createSubtestData(nil) + creator := subtestData.shipmentCreator + + mtoShipment := factory.BuildMTOShipment(nil, []factory.Customization{ + { + Model: subtestData.move, + LinkOnly: true, + }, + { + Model: models.Address{ + State: "AK", + }, + Type: &factory.Addresses.PickupAddress, + }, + { + Model: models.Address{ + State: "HI", + }, + Type: &factory.Addresses.DeliveryAddress, + }, + }, nil) + + mtoShipmentClear := clearShipmentIDFields(&mtoShipment) + mtoShipmentClear.MTOServiceItems = models.MTOServiceItems{} + + createdShipment, err := creator.CreateMTOShipment(suite.AppContextForTest(), mtoShipmentClear) + + suite.NoError(err) + suite.NotNil(createdShipment) + suite.Equal(models.MTOShipmentStatusDraft, createdShipment.Status) + suite.NotEmpty(createdShipment.PickupAddressID) + suite.NotEmpty(createdShipment.DestinationAddressID) + // both pickup and destination addresses should be OCONUS since Alaska & Hawaii are considered OCONUS + suite.True(*createdShipment.PickupAddress.IsOconus) + suite.True(*createdShipment.DestinationAddress.IsOconus) + suite.Equal(createdShipment.MarketCode, models.MarketCodeInternational) }) suite.Run("If the shipment has an international address it should be returned", func() { diff --git a/pkg/services/mto_shipment/mto_shipment_updater.go b/pkg/services/mto_shipment/mto_shipment_updater.go index c2660eb474c..ea0269a8720 100644 --- a/pkg/services/mto_shipment/mto_shipment_updater.go +++ b/pkg/services/mto_shipment/mto_shipment_updater.go @@ -461,6 +461,7 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, // Make sure the shipment has the updated DestinationAddressID to store // in mto_shipments table newShipment.DestinationAddressID = &newDestinationAddress.ID + newShipment.DestinationAddress = newDestinationAddress } else if newShipment.DestinationAddressID == nil { // There is no original address to update if newShipment.DestinationAddress.ID == uuid.Nil { @@ -471,6 +472,7 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, return newDestAddErr } newShipment.DestinationAddressID = &newDestinationAddress.ID + newShipment.DestinationAddress = newDestinationAddress } else { // Otherwise, there is no original address to update and this new address already has an ID newShipment.DestinationAddressID = &newShipment.DestinationAddress.ID @@ -493,6 +495,7 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, } newShipment.PickupAddressID = &newPickupAddress.ID + newShipment.PickupAddress = newPickupAddress } else if newShipment.PickupAddressID == nil { // There is no original address to update if newShipment.PickupAddress.ID == uuid.Nil { @@ -503,6 +506,7 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, return newPickupAddCreateErr } newShipment.PickupAddressID = &newPickupAddress.ID + newShipment.PickupAddress = newPickupAddress } else { // Otherwise, there is no original address to update and this new address already has an ID newShipment.PickupAddressID = &newShipment.PickupAddress.ID @@ -657,6 +661,7 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, } // Assign updated storage facility address to the updated shipment newShipment.StorageFacility.AddressID = newStorageFacilityAddress.ID + newShipment.StorageFacility.Address = *newStorageFacilityAddress } else { // Make sure that the new storage facility address doesn't already have an ID. // If it does, we just assign it. Otherwise, we need to create it. @@ -684,10 +689,13 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, // For NTS-Release set the pick up address to the storage facility if newShipment.ShipmentType == models.MTOShipmentTypeHHGOutOfNTSDom { newShipment.PickupAddressID = &newShipment.StorageFacility.AddressID + newShipment.PickupAddress = &newShipment.StorageFacility.Address + } // For NTS set the destination address to the storage facility if newShipment.ShipmentType == models.MTOShipmentTypeHHGIntoNTSDom { newShipment.DestinationAddressID = &newShipment.StorageFacility.AddressID + newShipment.DestinationAddress = &newShipment.StorageFacility.Address } } @@ -835,6 +843,20 @@ func (f *mtoShipmentUpdater) updateShipmentRecord(appCtx appcontext.AppContext, newShipment.SACType = dbShipment.SACType } + // when populating the market_code column, it is considered domestic if both pickup & dest are CONUS addresses + if newShipment.PickupAddress != nil && newShipment.DestinationAddress != nil && + newShipment.PickupAddress.IsOconus != nil && newShipment.DestinationAddress.IsOconus != nil { + pickupAddress := newShipment.PickupAddress + destAddress := newShipment.DestinationAddress + if !*pickupAddress.IsOconus && !*destAddress.IsOconus { + marketCodeDomestic := models.MarketCodeDomestic + newShipment.MarketCode = marketCodeDomestic + } else { + marketCodeInternational := models.MarketCodeInternational + newShipment.MarketCode = marketCodeInternational + } + } + if err := txnAppCtx.DB().Update(newShipment); err != nil { return err } diff --git a/pkg/services/mto_shipment/mto_shipment_updater_test.go b/pkg/services/mto_shipment/mto_shipment_updater_test.go index 724c3426b9e..321a98bc2bc 100644 --- a/pkg/services/mto_shipment/mto_shipment_updater_test.go +++ b/pkg/services/mto_shipment/mto_shipment_updater_test.go @@ -142,6 +142,7 @@ func (suite *MTOShipmentServiceSuite) TestMTOShipmentUpdater() { Status: oldMTOShipment.Status, ActualPickupDate: &actualPickupDate, ApprovedDate: &firstAvailableDeliveryDate, + MarketCode: oldMTOShipment.MarketCode, } primeEstimatedWeight = unit.Pound(9000) @@ -372,7 +373,7 @@ func (suite *MTOShipmentServiceSuite) TestMTOShipmentUpdater() { suite.Nil(newShipment.TertiaryDeliveryAddress) }) - suite.Run("Successful update to all address fields", func() { + suite.Run("Successful update to all address fields for domestic shipment", func() { setupTestData() // Ensure we can update every address field on the shipment @@ -393,13 +394,12 @@ func (suite *MTOShipmentServiceSuite) TestMTOShipmentUpdater() { HasSecondaryDeliveryAddress: models.BoolPointer(true), SecondaryDeliveryAddress: &secondaryDeliveryAddress, SecondaryDeliveryAddressID: &secondaryDeliveryAddress.ID, - - HasTertiaryPickupAddress: models.BoolPointer(true), - TertiaryPickupAddress: &tertiaryPickupAddress, - TertiaryPickupAddressID: &tertiaryPickupAddress.ID, - HasTertiaryDeliveryAddress: models.BoolPointer(true), - TertiaryDeliveryAddress: &tertiaryDeliveryAddress, - TertiaryDeliveryAddressID: &tertiaryDeliveryAddress.ID, + HasTertiaryPickupAddress: models.BoolPointer(true), + TertiaryPickupAddress: &tertiaryPickupAddress, + TertiaryPickupAddressID: &tertiaryPickupAddress.ID, + HasTertiaryDeliveryAddress: models.BoolPointer(true), + TertiaryDeliveryAddress: &tertiaryDeliveryAddress, + TertiaryDeliveryAddressID: &tertiaryDeliveryAddress.ID, } session := auth.Session{} updatedShipment, err := mtoShipmentUpdaterCustomer.UpdateMTOShipment(suite.AppContextWithSessionForTest(&session), updatedShipment, eTag, "test") @@ -418,9 +418,38 @@ func (suite *MTOShipmentServiceSuite) TestMTOShipmentUpdater() { suite.Equal(tertiaryPickupAddress.StreetAddress1, updatedShipment.TertiaryPickupAddress.StreetAddress1) suite.Equal(tertiaryDeliveryAddress.ID, *updatedShipment.TertiaryDeliveryAddressID) suite.Equal(tertiaryDeliveryAddress.StreetAddress1, updatedShipment.TertiaryDeliveryAddress.StreetAddress1) + suite.Equal(updatedShipment.MarketCode, models.MarketCodeDomestic) // Verify that shipment recalculate was handled correctly mockShipmentRecalculator.AssertNotCalled(suite.T(), "ShipmentRecalculatePaymentRequest", mock.AnythingOfType("*appcontext.appContext"), mock.AnythingOfType("uuid.UUID")) + }) + + suite.Run("Successful update to all address fields resulting in change of market code", func() { + setupTestData() + + previousShipment := factory.BuildMTOShipment(suite.DB(), nil, nil) + newDestinationAddress.State = "AK" + newPickupAddress.State = "HI" + // this should be "d" since it is default + suite.Equal(previousShipment.MarketCode, models.MarketCodeDomestic) + + eTag := etag.GenerateEtag(previousShipment.UpdatedAt) + updatedShipment := &models.MTOShipment{ + ID: previousShipment.ID, + DestinationAddress: &newDestinationAddress, + DestinationAddressID: &newDestinationAddress.ID, + PickupAddress: &newPickupAddress, + PickupAddressID: &newPickupAddress.ID, + } + session := auth.Session{} + updatedShipment, err := mtoShipmentUpdaterCustomer.UpdateMTOShipment(suite.AppContextWithSessionForTest(&session), updatedShipment, eTag, "test") + + suite.NoError(err) + suite.Equal(newDestinationAddress.ID, *updatedShipment.DestinationAddressID) + suite.True(*updatedShipment.DestinationAddress.IsOconus) + suite.Equal(newPickupAddress.ID, *updatedShipment.PickupAddressID) + suite.True(*updatedShipment.PickupAddress.IsOconus) + suite.Equal(updatedShipment.MarketCode, models.MarketCodeInternational) }) suite.Run("Successful update to a minimal MTO shipment", func() { diff --git a/pkg/services/orchestrators/shipment/shipment_creator.go b/pkg/services/orchestrators/shipment/shipment_creator.go index 0daa15a28aa..3690bf71429 100644 --- a/pkg/services/orchestrators/shipment/shipment_creator.go +++ b/pkg/services/orchestrators/shipment/shipment_creator.go @@ -1,6 +1,8 @@ package shipment import ( + "database/sql" + "github.com/transcom/mymove/pkg/appcontext" "github.com/transcom/mymove/pkg/models" "github.com/transcom/mymove/pkg/services" @@ -73,7 +75,6 @@ func (s *shipmentCreator) CreateShipment(appCtx appcontext.AppContext, shipment if !isPPMShipment { // Update PPMType once shipment gets created. _, err = s.moveTaskOrderUpdater.UpdatePPMType(txnAppCtx, mtoShipment.MoveTaskOrderID) - if err != nil { return err } @@ -84,16 +85,29 @@ func (s *shipmentCreator) CreateShipment(appCtx appcontext.AppContext, shipment mtoShipment.PPMShipment.Shipment = *mtoShipment _, err = s.ppmShipmentCreator.CreatePPMShipmentWithDefaultCheck(txnAppCtx, mtoShipment.PPMShipment) - if err != nil { return err } + // Update PPMType once shipment gets created. _, err = s.moveTaskOrderUpdater.UpdatePPMType(txnAppCtx, mtoShipment.MoveTaskOrderID) - if err != nil { return err } + + // getting updated shipment since market code value was updated after PPM creation + var updatedShipment models.MTOShipment + err = txnAppCtx.DB().Find(&updatedShipment, mtoShipment.ID) + if err != nil && err != sql.ErrNoRows { + return err + } + if mtoShipment.MarketCode != updatedShipment.MarketCode { + mtoShipment.MarketCode = updatedShipment.MarketCode + } + // since the shipment was updated, we need to ensure we have the most recent eTag + if mtoShipment.UpdatedAt != updatedShipment.UpdatedAt { + mtoShipment.UpdatedAt = updatedShipment.UpdatedAt + } return nil } else if isBoatShipment { mtoShipment.BoatShipment.ShipmentID = mtoShipment.ID diff --git a/pkg/services/ppmshipment/ppm_shipment_creator.go b/pkg/services/ppmshipment/ppm_shipment_creator.go index a87b94565ab..a8a6135664f 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator.go @@ -62,6 +62,7 @@ func (f *ppmShipmentCreator) createPPMShipment(appCtx appcontext.AppContext, ppm return fmt.Errorf("failed to create pickup address %e", err) } ppmShipment.PickupAddressID = &address.ID + ppmShipment.PickupAddress = address } if ppmShipment.SecondaryPickupAddress != nil { @@ -90,6 +91,7 @@ func (f *ppmShipmentCreator) createPPMShipment(appCtx appcontext.AppContext, ppm return fmt.Errorf("failed to create destination address %e", err) } ppmShipment.DestinationAddressID = &address.ID + ppmShipment.DestinationAddress = address } if ppmShipment.SecondaryDestinationAddress != nil { @@ -127,6 +129,27 @@ func (f *ppmShipmentCreator) createPPMShipment(appCtx appcontext.AppContext, ppm // Validate ppm shipment model object and save it to DB verrs, err := txnAppCtx.DB().ValidateAndCreate(ppmShipment) + // updating the shipment after PPM creation due to addresses not being created until PPM shipment is created + // when populating the market_code column, it is considered domestic if both pickup & dest on the PPM are CONUS addresses + var mtoShipment models.MTOShipment + if ppmShipment.PickupAddress != nil && ppmShipment.DestinationAddress != nil && + ppmShipment.PickupAddress.IsOconus != nil && ppmShipment.DestinationAddress.IsOconus != nil { + err = txnAppCtx.DB().Find(&mtoShipment, ppmShipment.ShipmentID) + pickupAddress := ppmShipment.PickupAddress + destAddress := ppmShipment.DestinationAddress + if !*pickupAddress.IsOconus && !*destAddress.IsOconus { + marketCodeDomestic := models.MarketCodeDomestic + mtoShipment.MarketCode = marketCodeDomestic + } else { + marketCodeInternational := models.MarketCodeInternational + mtoShipment.MarketCode = marketCodeInternational + } + if err := txnAppCtx.DB().Update(&mtoShipment); err != nil { + return err + } + ppmShipment.Shipment = mtoShipment + } + // Check validation errors if verrs != nil && verrs.HasAny() { return apperror.NewInvalidInputError(uuid.Nil, err, verrs, "Invalid input found while creating the PPM shipment.") diff --git a/pkg/services/ppmshipment/ppm_shipment_creator_test.go b/pkg/services/ppmshipment/ppm_shipment_creator_test.go index 0271ace37e1..596ea5627e7 100644 --- a/pkg/services/ppmshipment/ppm_shipment_creator_test.go +++ b/pkg/services/ppmshipment/ppm_shipment_creator_test.go @@ -61,10 +61,10 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { return subtestData } - suite.Run("Can successfully create a PPMShipment", func() { + suite.Run("Can successfully create a domestic PPMShipment", func() { // Under test: CreatePPMShipment // Set up: Established valid shipment and valid new PPM shipment - // Expected: New PPM shipment successfully created + // Expected: New PPM shipment successfully created, market code is "d" on the parent shipment appCtx := suite.AppContextForTest() // Set required fields for PPMShipment @@ -102,6 +102,49 @@ func (suite *PPMShipmentSuite) TestPPMShipmentCreator() { suite.Nil(err) suite.NotNil(createdPPMShipment) + suite.Equal(createdPPMShipment.Shipment.MarketCode, models.MarketCodeDomestic) + }) + + suite.Run("Can successfully create an international PPMShipment", func() { + // Under test: CreatePPMShipment + // Set up: Established valid shipment and valid new PPM shipment + // Expected: New PPM shipment successfully created, market code is "i" on the parent shipment + appCtx := suite.AppContextForTest() + + // Set required fields for PPMShipment + subtestData := createSubtestData(models.PPMShipment{ + ExpectedDepartureDate: testdatagen.NextValidMoveDate, + SITExpected: models.BoolPointer(false), + PickupAddress: &models.Address{ + StreetAddress1: "987 Other Avenue", + StreetAddress2: models.StringPointer("P.O. Box 1234"), + StreetAddress3: models.StringPointer("c/o Another Person"), + City: "Fairbanks", + State: "AK", + PostalCode: "99507", + }, + DestinationAddress: &models.Address{ + StreetAddress1: "987 Other Avenue", + StreetAddress2: models.StringPointer("P.O. Box 12345"), + StreetAddress3: models.StringPointer("c/o Another Person"), + City: "Fort Hawaiir", + State: "HI", + PostalCode: "96821", + }, + }, nil) + + ppmEstimator.On( + "EstimateIncentiveWithDefaultChecks", + mock.AnythingOfType("*appcontext.appContext"), + mock.AnythingOfType("models.PPMShipment"), + mock.AnythingOfType("*models.PPMShipment"), + ).Return(nil, nil, nil).Once() + + createdPPMShipment, err := ppmShipmentCreator.CreatePPMShipmentWithDefaultCheck(appCtx, subtestData.newPPMShipment) + + suite.Nil(err) + suite.NotNil(createdPPMShipment) + suite.Equal(createdPPMShipment.Shipment.MarketCode, models.MarketCodeInternational) }) var invalidInputTests = []struct { 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 2e5a08a300f..1b75b668336 100644 --- a/pkg/services/shipment_address_update/shipment_address_update_requester.go +++ b/pkg/services/shipment_address_update/shipment_address_update_requester.go @@ -544,6 +544,26 @@ func (f *shipmentAddressUpdateRequester) ReviewShipmentAddressChange(appCtx appc addressUpdate.Shipment.MTOServiceItems = append(addressUpdate.Shipment.MTOServiceItems, regeneratedServiceItems...) } } + + // handling NTS shipments that don't have a pickup address + var pickupAddress models.Address + if shipment.ShipmentType == models.MTOShipmentTypeHHGOutOfNTSDom { + pickupAddress = shipment.StorageFacility.Address + } else { + pickupAddress = *shipment.PickupAddress + } + // need to assess if the shipment's market code should change + // when populating the market_code column, it is considered domestic if both pickup & the NEW dest are CONUS addresses + if pickupAddress.IsOconus != nil && addressUpdate.NewAddress.IsOconus != nil { + newAddress := addressUpdate.NewAddress + if !*pickupAddress.IsOconus && !*newAddress.IsOconus { + marketCodeDomestic := models.MarketCodeDomestic + shipment.MarketCode = marketCodeDomestic + } else { + marketCodeInternational := models.MarketCodeInternational + shipment.MarketCode = marketCodeInternational + } + } } if tooApprovalStatus == models.ShipmentAddressUpdateStatusRejected { 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 5883a6bcc1e..37b1f6f4457 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 @@ -102,6 +102,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.Equal(newAddress.State, updatedShipment.DestinationAddress.State) suite.Equal(newAddress.City, updatedShipment.DestinationAddress.City) }) + suite.Run("Update with invalid etag should fail", func() { move := setupTestData() shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), nil, nil) @@ -184,6 +185,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.NoError(err) suite.NotNil(update) }) + suite.Run("Should not be able to update NTS shipment", func() { move := setupTestData() newAddress := models.Address{ @@ -202,6 +204,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.Error(err) suite.Nil(update) }) + suite.Run("Should be able to update NTSr shipment", func() { move := setupTestData() newAddress := models.Address{ @@ -225,6 +228,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.NoError(err) suite.NotNil(update) }) + suite.Run("Request destination address changes on the same shipment multiple times", func() { move := setupTestData() shipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), nil, nil) @@ -262,6 +266,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.Equal(models.ShipmentAddressUpdateStatusRequested, update.Status) suite.Equal("we really need to change the address again", update.ContractorRemarks) }) + suite.Run("Shorthaul to linehaul should be flagged", func() { mockPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), @@ -306,6 +311,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.NoError(err) suite.Equal(models.MoveStatusAPPROVALSREQUESTED, updatedMove.Status) }) + suite.Run("linehaul to shorthaul should be flagged", func() { mockPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), @@ -350,6 +356,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.NoError(err) suite.Equal(models.MoveStatusAPPROVALSREQUESTED, updatedMove.Status) }) + suite.Run("service area change should be flagged", func() { mockPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"), @@ -435,6 +442,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.NoError(err) suite.Equal(models.MoveStatusAPPROVALSREQUESTED, updatedMove.Status) }) + suite.Run("mileage bracket change should be flagged", func() { originalDomesticServiceArea := testdatagen.FetchOrMakeReDomesticServiceArea(suite.DB(), testdatagen.Assertions{ ReDomesticServiceArea: models.ReDomesticServiceArea{ @@ -499,6 +507,7 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestCreateApprovedShipmentAddres suite.NoError(err) suite.Equal(models.MoveStatusAPPROVALSREQUESTED, updatedMove.Status) }) + suite.Run("destination address request succeeds when containing destination SIT", func() { move := setupTestData() newAddress := models.Address{ @@ -645,7 +654,6 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp }) suite.Run("TOO approves address change and service items final destination address changes", func() { - // creating an address change that shares the same address to avoid hitting lineHaulChange check addressChange := factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ { @@ -713,6 +721,71 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp // delivery and final destination addresses should be the same suite.Equal(updatedShipment.DestinationAddressID, updatedShipment.MTOServiceItems[0].SITDestinationFinalAddressID) }) + + suite.Run("TOO approves address change that triggers market code change of shipment", func() { + addressChange := factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: "123 Main St", + StreetAddress2: models.StringPointer("Apt 2"), + StreetAddress3: models.StringPointer("Suite 200"), + City: "New York", + State: "NY", + PostalCode: "10001", + }, + Type: &factory.Addresses.OriginalAddress, + }, + { + Model: models.Address{ + StreetAddress1: "456 Northern Lights Blvd", + StreetAddress2: models.StringPointer("Apt 5B"), + StreetAddress3: models.StringPointer("Suite 300"), + City: "Anchorage", + State: "AK", + PostalCode: "99503", + IsOconus: models.BoolPointer(true), + }, + Type: &factory.Addresses.NewAddress, + }, + }, nil) + shipment := addressChange.Shipment + reService := factory.BuildDDFSITReService(suite.DB()) + sitDestinationOriginalAddress := factory.BuildAddress(suite.DB(), nil, nil) + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + ID: shipment.MoveTaskOrderID, + }, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: reService, + LinkOnly: true, + }, + { + Model: sitDestinationOriginalAddress, + LinkOnly: true, + Type: &factory.Addresses.SITDestinationOriginalAddress, + }, + }, nil) + officeRemarks := "Changing to OCONUS address" + + // check to make sure the market code is "d" prior to updating with OCONUS address + suite.Equal(shipment.MarketCode, models.MarketCodeDomestic) + update, err := addressUpdateRequester.ReviewShipmentAddressChange(suite.AppContextForTest(), addressChange.Shipment.ID, "APPROVED", officeRemarks) + suite.NoError(err) + suite.NotNil(update) + + // Make sure the market code changed on the shipment + var updatedShipment models.MTOShipment + err = suite.DB().EagerPreload("DestinationAddress", "MTOServiceItems").Find(&updatedShipment, update.ShipmentID) + suite.NoError(err) + + suite.Equal(updatedShipment.MarketCode, models.MarketCodeInternational) + }) } func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUpdateRequestChangedPricing() { @@ -780,12 +853,14 @@ func (suite *ShipmentAddressUpdateServiceSuite) TestTOOApprovedShipmentAddressUp { Model: models.Address{ PostalCode: "89523", + IsOconus: models.BoolPointer(false), }, Type: &factory.Addresses.PickupAddress, }, { Model: models.Address{ PostalCode: "90210", + IsOconus: models.BoolPointer(false), }, Type: &factory.Addresses.DeliveryAddress, }, diff --git a/pkg/testdatagen/make_mto_shipment.go b/pkg/testdatagen/make_mto_shipment.go index 03f27a329ec..7dc20fb63e8 100644 --- a/pkg/testdatagen/make_mto_shipment.go +++ b/pkg/testdatagen/make_mto_shipment.go @@ -148,6 +148,7 @@ func makeMTOShipment(db *pop.Connection, assertions Assertions) models.MTOShipme Status: shipmentStatus, StorageFacilityID: storageFacilityID, StorageFacility: storageFacilityPtr, + MarketCode: models.MarketCodeDomestic, } if assertions.MTOShipment.DestinationType != nil { diff --git a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js index c81614027c2..fa9cdecfeda 100644 --- a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js +++ b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js @@ -428,7 +428,7 @@ test.describe('Services counselor user', () => { await page.getByRole('button', { name: 'Confirm' }).click(); await scPage.waitForPage.moveDetails(); - await expect(page.getByTestId('ShipmentContainer').getByTestId('tag')).toContainText('packet ready for download'); + await expect(page.getByText('PACKET READY FOR DOWNLOAD')).toBeVisible(); // Navigate to the "View documents" page await expect(page.getByRole('button', { name: /View documents/i })).toBeVisible(); @@ -454,7 +454,7 @@ test.describe('Services counselor user', () => { await page.getByTestId('reviewDocumentsContinueButton').click(); await scPage.waitForPage.moveDetails(); - await expect(page.getByTestId('ShipmentContainer').getByTestId('tag')).toContainText('packet ready for download'); + await expect(page.getByText('PACKET READY FOR DOWNLOAD')).toBeVisible(); }); test.describe('Edit shipment info and incentives', () => { diff --git a/swagger-def/definitions/MTOShipment.yaml b/swagger-def/definitions/MTOShipment.yaml index 68c3a55f80a..2f7e723ab16 100644 --- a/swagger-def/definitions/MTOShipment.yaml +++ b/swagger-def/definitions/MTOShipment.yaml @@ -210,3 +210,11 @@ properties: destinationSitAuthEndDate: format: date-time type: string + marketCode: + type: string + enum: + - 'd' + - 'i' + example: 'd' + description: 'Single-letter designator for domestic (d) or international (i) shipments' + diff --git a/swagger-def/definitions/prime/MTOShipmentWithoutServiceItems.yaml b/swagger-def/definitions/prime/MTOShipmentWithoutServiceItems.yaml index dd229ad83a5..d8393132c28 100644 --- a/swagger-def/definitions/prime/MTOShipmentWithoutServiceItems.yaml +++ b/swagger-def/definitions/prime/MTOShipmentWithoutServiceItems.yaml @@ -234,3 +234,10 @@ properties: type: string description: The SIT authorized end date for destination SIT. x-nullable: true + marketCode: + type: string + enum: + - 'd' + - 'i' + example: 'd' + description: 'Single-letter designator for domestic (d) or international (i) shipments' diff --git a/swagger-def/definitions/prime/v2/MTOShipmentWithoutServiceItems.yaml b/swagger-def/definitions/prime/v2/MTOShipmentWithoutServiceItems.yaml index ce4d09fa639..233fbc5a04d 100644 --- a/swagger-def/definitions/prime/v2/MTOShipmentWithoutServiceItems.yaml +++ b/swagger-def/definitions/prime/v2/MTOShipmentWithoutServiceItems.yaml @@ -238,3 +238,10 @@ properties: type: string description: The SIT authorized end date for destination SIT. x-nullable: true + marketCode: + type: string + enum: + - 'd' + - 'i' + example: 'd' + description: 'Single-letter designator for domestic (d) or international (i) shipments' \ No newline at end of file diff --git a/swagger-def/definitions/prime/v3/MTOShipmentWithoutServiceItems.yaml b/swagger-def/definitions/prime/v3/MTOShipmentWithoutServiceItems.yaml index f97995ff680..1720c743a36 100644 --- a/swagger-def/definitions/prime/v3/MTOShipmentWithoutServiceItems.yaml +++ b/swagger-def/definitions/prime/v3/MTOShipmentWithoutServiceItems.yaml @@ -238,3 +238,10 @@ properties: type: string description: The SIT authorized end date for destination SIT. x-nullable: true + marketCode: + type: string + enum: + - 'd' + - 'i' + example: 'd' + description: 'Single-letter designator for domestic (d) or international (i) shipments' diff --git a/swagger-def/internal.yaml b/swagger-def/internal.yaml index e1def8dfbe5..63f46f68d6d 100644 --- a/swagger-def/internal.yaml +++ b/swagger-def/internal.yaml @@ -1879,6 +1879,13 @@ definitions: x-nullable: true readOnly: true example: '1K43AR-01' + marketCode: + type: string + enum: + - 'd' + - 'i' + example: 'd' + description: 'Single-letter designator for domestic (d) or international (i) shipments' MTOShipments: items: $ref: '#/definitions/MTOShipment' diff --git a/swagger-def/support.yaml b/swagger-def/support.yaml index 87b20fbcafb..5a023764486 100644 --- a/swagger-def/support.yaml +++ b/swagger-def/support.yaml @@ -1468,6 +1468,13 @@ definitions: pointOfContact: type: string description: Email or id of a contact person for this update. + marketCode: + type: string + enum: + - 'd' + - 'i' + example: 'd' + description: 'Single-letter designator for domestic (d) or international (i) shipments' MTOShipments: items: $ref: '#/definitions/MTOShipment' diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index 5064fae8f1b..66f4d879f05 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -9966,6 +9966,15 @@ definitions: destinationSitAuthEndDate: format: date-time type: string + marketCode: + type: string + enum: + - d + - i + example: d + description: >- + Single-letter designator for domestic (d) or international (i) + shipments LOATypeNullable: description: The Line of accounting (TAC/SAC) type that will be used for the shipment type: string diff --git a/swagger/internal.yaml b/swagger/internal.yaml index 52d6029bd74..0a7a881723a 100644 --- a/swagger/internal.yaml +++ b/swagger/internal.yaml @@ -1906,6 +1906,15 @@ definitions: x-nullable: true readOnly: true example: 1K43AR-01 + marketCode: + type: string + enum: + - d + - i + example: d + description: >- + Single-letter designator for domestic (d) or international (i) + shipments MTOShipments: items: $ref: '#/definitions/MTOShipment' diff --git a/swagger/prime.yaml b/swagger/prime.yaml index 546f5a800f2..236df060e26 100644 --- a/swagger/prime.yaml +++ b/swagger/prime.yaml @@ -4185,6 +4185,15 @@ definitions: type: string description: The SIT authorized end date for destination SIT. x-nullable: true + marketCode: + type: string + enum: + - d + - i + example: d + description: >- + Single-letter designator for domestic (d) or international (i) + shipments MTOShipmentsWithoutServiceObjects: description: A list of shipments without their associated service items. items: diff --git a/swagger/prime_v2.yaml b/swagger/prime_v2.yaml index 3392e4f18f5..8fc2194c8f0 100644 --- a/swagger/prime_v2.yaml +++ b/swagger/prime_v2.yaml @@ -2874,6 +2874,15 @@ definitions: type: string description: The SIT authorized end date for destination SIT. x-nullable: true + marketCode: + type: string + enum: + - d + - i + example: d + description: >- + Single-letter designator for domestic (d) or international (i) + shipments MTOShipmentsWithoutServiceObjects: description: A list of shipments without their associated service items. items: diff --git a/swagger/prime_v3.yaml b/swagger/prime_v3.yaml index 86d7f3a7453..f4cc2e8b1ab 100644 --- a/swagger/prime_v3.yaml +++ b/swagger/prime_v3.yaml @@ -3115,6 +3115,15 @@ definitions: type: string description: The SIT authorized end date for destination SIT. x-nullable: true + marketCode: + type: string + enum: + - d + - i + example: d + description: >- + Single-letter designator for domestic (d) or international (i) + shipments MTOShipmentsWithoutServiceObjects: description: A list of shipments without their associated service items. items: diff --git a/swagger/support.yaml b/swagger/support.yaml index e2bd46ad505..c6dff7a912e 100644 --- a/swagger/support.yaml +++ b/swagger/support.yaml @@ -1579,6 +1579,15 @@ definitions: pointOfContact: type: string description: Email or id of a contact person for this update. + marketCode: + type: string + enum: + - d + - i + example: d + description: >- + Single-letter designator for domestic (d) or international (i) + shipments MTOShipments: items: $ref: '#/definitions/MTOShipment'