From 81f7b95206b5f1a2c85734627e4ad28a861756e5 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 10 Dec 2024 16:11:02 +0000 Subject: [PATCH 01/21] initial commit, using existing work from 21940 but will change this to a db func --- migrations/app/migrations_manifest.txt | 1 + ...73216_add_destination_queue_db_func.up.sql | 106 +++ pkg/gen/ghcapi/configure_mymove.go | 5 + pkg/gen/ghcapi/embedded_spec.go | 326 +++++++++ pkg/gen/ghcapi/ghcoperations/mymove_api.go | 12 + .../queues/get_destination_requests_queue.go | 58 ++ ...t_destination_requests_queue_parameters.go | 644 ++++++++++++++++++ ...et_destination_requests_queue_responses.go | 149 ++++ ...t_destination_requests_queue_urlbuilder.go | 274 ++++++++ pkg/handlers/ghcapi/api.go | 7 + pkg/handlers/ghcapi/queues.go | 126 ++++ pkg/services/mocks/OrderFetcher.go | 37 + pkg/services/order.go | 1 + pkg/services/order/order_fetcher.go | 148 +++- src/constants/routes.js | 6 +- src/hooks/queries.js | 23 + src/pages/Office/MoveQueue/MoveQueue.jsx | 44 +- src/services/ghcApi.js | 16 + swagger-def/ghc.yaml | 112 +++ swagger/ghc.yaml | 119 ++++ 20 files changed, 2209 insertions(+), 5 deletions(-) create mode 100644 migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql create mode 100644 pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go create mode 100644 pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go create mode 100644 pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go create mode 100644 pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index b1d24b20447..fefc26f6685 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1075,3 +1075,4 @@ 20250113201232_update_estimated_pricing_procs_add_is_peak_func.up.sql 20250116200912_disable_homesafe_stg_cert.up.sql 20250120144247_update_pricing_proc_to_use_110_percent_weight.up.sql +20250123173216_add_destination_queue_db_func.up.sql diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql new file mode 100644 index 00000000000..8808b472e68 --- /dev/null +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql @@ -0,0 +1,106 @@ +CREATE OR REPLACE FUNCTION get_destination_queue( + move_code TEXT DEFAULT NULL, -- Search parameter for Move Code + input_move_id UUID DEFAULT NULL, -- Search parameter for Move ID + page INTEGER DEFAULT 1, -- Page number for pagination + per_page INTEGER DEFAULT 20, -- Number of results per page + branch TEXT DEFAULT NULL, -- Filter: service_member.affiliation + edipi TEXT DEFAULT NULL, -- Filter: service_member.edipi + emplid TEXT DEFAULT NULL, -- Filter: service_member.emplid + customer_name TEXT DEFAULT NULL, -- Filter: service_member.first_name + last_name + destination_duty_location TEXT DEFAULT NULL,-- Filter: orders.new_duty_location_id.name + origin_duty_location TEXT DEFAULT NULL, -- Filter: orders.origin_duty_location_id.name + origin_gbloc TEXT DEFAULT NULL, -- Filter: move.counseling_office_transportation_office.gbloc + submitted_at TIMESTAMP DEFAULT NULL, -- Filter: moves.submitted_at + appeared_in_too_at TIMESTAMP DEFAULT NULL, -- Filter: moves.appeared_in_too_at + too_assigned_user TEXT DEFAULT NULL -- Filter: moves.too_assigned_id -> office_users.first_name + last_name +) +RETURNS TABLE ( + move_id UUID, + locator TEXT, + orders_id UUID, + available_to_prime_at TIMESTAMP WITH TIME ZONE, + show BOOLEAN, + total_count BIGINT +) AS $$ +DECLARE + sql_query TEXT; + offset_value INTEGER; +BEGIN + -- OFFSET for pagination + offset_value := (page - 1) * per_page; + + sql_query := ' + SELECT moves.id AS move_id, + moves.locator::TEXT AS locator, + moves.orders_id, + moves.available_to_prime_at, + moves.show, + COUNT(*) OVER() AS total_count + FROM moves + INNER JOIN orders ON moves.orders_id = orders.id + INNER JOIN service_members ON orders.service_member_id = service_members.id + LEFT JOIN duty_locations AS new_duty_locations ON orders.new_duty_location_id = new_duty_locations.id + LEFT JOIN duty_locations AS origin_duty_locations ON orders.origin_duty_location_id = origin_duty_locations.id + LEFT JOIN office_users ON moves.too_assigned_id = office_users.id + LEFT JOIN transportation_offices AS counseling_offices + ON moves.counseling_transportation_office_id = counseling_offices.id + WHERE moves.available_to_prime_at IS NOT NULL + AND moves.show = TRUE + '; + + -- add dynamic filters based on provided parameters + IF move_code IS NOT NULL THEN + sql_query := sql_query || ' AND moves.locator ILIKE ''%' || UPPER(move_code) || '%'' '; + END IF; + + IF input_move_id IS NOT NULL THEN + sql_query := sql_query || ' AND moves.id = ''' || input_move_id || ''' '; + END IF; + + IF branch IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%' || branch || '%'' '; + END IF; + + IF edipi IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.edipi ILIKE ''%' || edipi || '%'' '; + END IF; + + IF emplid IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.emplid ILIKE ''%' || emplid || '%'' '; + END IF; + + IF customer_name IS NOT NULL THEN + sql_query := sql_query || ' AND (service_members.first_name || '' '' || service_members.last_name) ILIKE ''%' || customer_name || '%'' '; + END IF; + + IF destination_duty_location IS NOT NULL THEN + sql_query := sql_query || ' AND new_duty_locations.name ILIKE ''%' || destination_duty_location || '%'' '; + END IF; + + IF origin_duty_location IS NOT NULL THEN + sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%' || origin_duty_location || '%'' '; + END IF; + + IF origin_gbloc IS NOT NULL THEN + sql_query := sql_query || ' AND counseling_offices.gbloc ILIKE ''%' || origin_gbloc || '%'' '; + END IF; + + IF submitted_at IS NOT NULL THEN + sql_query := sql_query || ' AND moves.submitted_at = ''' || submitted_at || ''' '; + END IF; + + IF appeared_in_too_at IS NOT NULL THEN + sql_query := sql_query || ' AND moves.appeared_in_too_at = ''' || appeared_in_too_at || ''' '; + END IF; + + IF too_assigned_user IS NOT NULL THEN + sql_query := sql_query || ' AND (office_users.first_name || '' '' || office_users.last_name) ILIKE ''%' || too_assigned_user || '%'' '; + END IF; + + sql_query := sql_query || ' ORDER BY moves.id ASC '; + sql_query := sql_query || ' LIMIT ' || per_page || ' OFFSET ' || offset_value || ' '; + + RETURN QUERY EXECUTE sql_query; + +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/pkg/gen/ghcapi/configure_mymove.go b/pkg/gen/ghcapi/configure_mymove.go index 32eb5174c09..08d71eb7034 100644 --- a/pkg/gen/ghcapi/configure_mymove.go +++ b/pkg/gen/ghcapi/configure_mymove.go @@ -242,6 +242,11 @@ func configureAPI(api *ghcoperations.MymoveAPI) http.Handler { return middleware.NotImplemented("operation customer_support_remarks.GetCustomerSupportRemarksForMove has not yet been implemented") }) } + if api.QueuesGetDestinationRequestsQueueHandler == nil { + api.QueuesGetDestinationRequestsQueueHandler = queues.GetDestinationRequestsQueueHandlerFunc(func(params queues.GetDestinationRequestsQueueParams) middleware.Responder { + return middleware.NotImplemented("operation queues.GetDestinationRequestsQueue has not yet been implemented") + }) + } if api.GhcDocumentsGetDocumentHandler == nil { api.GhcDocumentsGetDocumentHandler = ghc_documents.GetDocumentHandlerFunc(func(params ghc_documents.GetDocumentParams) middleware.Responder { return middleware.NotImplemented("operation ghc_documents.GetDocument has not yet been implemented") diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 3db3ec66e71..878032b252f 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -4676,6 +4676,166 @@ func init() { } } }, + "/queues/destination-requests": { + "get": { + "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved.\n", + "produces": [ + "application/json" + ], + "tags": [ + "queues" + ], + "summary": "Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests)", + "operationId": "getDestinationRequestsQueue", + "parameters": [ + { + "type": "integer", + "description": "requested page of results", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "results per page", + "name": "perPage", + "in": "query" + }, + { + "enum": [ + "customerName", + "edipi", + "emplid", + "branch", + "locator", + "status", + "originDutyLocation", + "destinationDutyLocation", + "requestedMoveDate", + "appearedInTooAt", + "assignedTo", + "counselingOffice" + ], + "type": "string", + "description": "field that results should be sorted by", + "name": "sort", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "description": "direction of sort order if applied", + "name": "order", + "in": "query" + }, + { + "type": "string", + "name": "branch", + "in": "query" + }, + { + "type": "string", + "name": "locator", + "in": "query" + }, + { + "type": "string", + "name": "customerName", + "in": "query" + }, + { + "type": "string", + "name": "edipi", + "in": "query" + }, + { + "type": "string", + "name": "emplid", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "name": "originDutyLocation", + "in": "query" + }, + { + "type": "string", + "name": "destinationDutyLocation", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "name": "appearedInTooAt", + "in": "query" + }, + { + "type": "string", + "description": "filters the requested pickup date of a shipment on the move", + "name": "requestedMoveDate", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "enum": [ + "APPROVALS REQUESTED" + ], + "type": "string" + }, + "description": "Filtering for the status.", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "order type", + "name": "orderType", + "in": "query" + }, + { + "type": "string", + "description": "Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role.\n", + "name": "viewAsGBLOC", + "in": "query" + }, + { + "type": "string", + "description": "Used to illustrate which user is assigned to this move.\n", + "name": "assignedTo", + "in": "query" + }, + { + "type": "string", + "description": "filters using a counselingOffice name of the move", + "name": "counselingOffice", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully returned all moves matching the criteria", + "schema": { + "$ref": "#/definitions/QueueMovesResult" + } + }, + "403": { + "$ref": "#/responses/PermissionDenied" + }, + "500": { + "$ref": "#/responses/ServerError" + } + } + } + }, "/queues/moves": { "get": { "description": "An office TOO user will be assigned a transportation office that will determine which moves are displayed in their queue based on the origin duty location. GHC moves will show up here onced they have reached the submitted status sent by the customer and have move task orders, shipments, and service items to approve.\n", @@ -21336,6 +21496,172 @@ func init() { } } }, + "/queues/destination-requests": { + "get": { + "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved.\n", + "produces": [ + "application/json" + ], + "tags": [ + "queues" + ], + "summary": "Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests)", + "operationId": "getDestinationRequestsQueue", + "parameters": [ + { + "type": "integer", + "description": "requested page of results", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "results per page", + "name": "perPage", + "in": "query" + }, + { + "enum": [ + "customerName", + "edipi", + "emplid", + "branch", + "locator", + "status", + "originDutyLocation", + "destinationDutyLocation", + "requestedMoveDate", + "appearedInTooAt", + "assignedTo", + "counselingOffice" + ], + "type": "string", + "description": "field that results should be sorted by", + "name": "sort", + "in": "query" + }, + { + "enum": [ + "asc", + "desc" + ], + "type": "string", + "description": "direction of sort order if applied", + "name": "order", + "in": "query" + }, + { + "type": "string", + "name": "branch", + "in": "query" + }, + { + "type": "string", + "name": "locator", + "in": "query" + }, + { + "type": "string", + "name": "customerName", + "in": "query" + }, + { + "type": "string", + "name": "edipi", + "in": "query" + }, + { + "type": "string", + "name": "emplid", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "name": "originDutyLocation", + "in": "query" + }, + { + "type": "string", + "name": "destinationDutyLocation", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "name": "appearedInTooAt", + "in": "query" + }, + { + "type": "string", + "description": "filters the requested pickup date of a shipment on the move", + "name": "requestedMoveDate", + "in": "query" + }, + { + "uniqueItems": true, + "type": "array", + "items": { + "enum": [ + "APPROVALS REQUESTED" + ], + "type": "string" + }, + "description": "Filtering for the status.", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "order type", + "name": "orderType", + "in": "query" + }, + { + "type": "string", + "description": "Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role.\n", + "name": "viewAsGBLOC", + "in": "query" + }, + { + "type": "string", + "description": "Used to illustrate which user is assigned to this move.\n", + "name": "assignedTo", + "in": "query" + }, + { + "type": "string", + "description": "filters using a counselingOffice name of the move", + "name": "counselingOffice", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully returned all moves matching the criteria", + "schema": { + "$ref": "#/definitions/QueueMovesResult" + } + }, + "403": { + "description": "The request was denied", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "500": { + "description": "A server error occurred", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, "/queues/moves": { "get": { "description": "An office TOO user will be assigned a transportation office that will determine which moves are displayed in their queue based on the origin duty location. GHC moves will show up here onced they have reached the submitted status sent by the customer and have move task orders, shipments, and service items to approve.\n", diff --git a/pkg/gen/ghcapi/ghcoperations/mymove_api.go b/pkg/gen/ghcapi/ghcoperations/mymove_api.go index c53c0fec4d7..61bda14b7d3 100644 --- a/pkg/gen/ghcapi/ghcoperations/mymove_api.go +++ b/pkg/gen/ghcapi/ghcoperations/mymove_api.go @@ -173,6 +173,9 @@ func NewMymoveAPI(spec *loads.Document) *MymoveAPI { CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler: customer_support_remarks.GetCustomerSupportRemarksForMoveHandlerFunc(func(params customer_support_remarks.GetCustomerSupportRemarksForMoveParams) middleware.Responder { return middleware.NotImplemented("operation customer_support_remarks.GetCustomerSupportRemarksForMove has not yet been implemented") }), + QueuesGetDestinationRequestsQueueHandler: queues.GetDestinationRequestsQueueHandlerFunc(func(params queues.GetDestinationRequestsQueueParams) middleware.Responder { + return middleware.NotImplemented("operation queues.GetDestinationRequestsQueue has not yet been implemented") + }), GhcDocumentsGetDocumentHandler: ghc_documents.GetDocumentHandlerFunc(func(params ghc_documents.GetDocumentParams) middleware.Responder { return middleware.NotImplemented("operation ghc_documents.GetDocument has not yet been implemented") }), @@ -509,6 +512,8 @@ type MymoveAPI struct { CustomerGetCustomerHandler customer.GetCustomerHandler // CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler sets the operation handler for the get customer support remarks for move operation CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler customer_support_remarks.GetCustomerSupportRemarksForMoveHandler + // QueuesGetDestinationRequestsQueueHandler sets the operation handler for the get destination requests queue operation + QueuesGetDestinationRequestsQueueHandler queues.GetDestinationRequestsQueueHandler // GhcDocumentsGetDocumentHandler sets the operation handler for the get document operation GhcDocumentsGetDocumentHandler ghc_documents.GetDocumentHandler // MoveTaskOrderGetEntitlementsHandler sets the operation handler for the get entitlements operation @@ -842,6 +847,9 @@ func (o *MymoveAPI) Validate() error { if o.CustomerSupportRemarksGetCustomerSupportRemarksForMoveHandler == nil { unregistered = append(unregistered, "customer_support_remarks.GetCustomerSupportRemarksForMoveHandler") } + if o.QueuesGetDestinationRequestsQueueHandler == nil { + unregistered = append(unregistered, "queues.GetDestinationRequestsQueueHandler") + } if o.GhcDocumentsGetDocumentHandler == nil { unregistered = append(unregistered, "ghc_documents.GetDocumentHandler") } @@ -1295,6 +1303,10 @@ func (o *MymoveAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } + o.handlers["GET"]["/queues/destination-requests"] = queues.NewGetDestinationRequestsQueue(o.context, o.QueuesGetDestinationRequestsQueueHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } o.handlers["GET"]["/documents/{documentId}"] = ghc_documents.NewGetDocument(o.context, o.GhcDocumentsGetDocumentHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go new file mode 100644 index 00000000000..f4fdf4135d3 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetDestinationRequestsQueueHandlerFunc turns a function with the right signature into a get destination requests queue handler +type GetDestinationRequestsQueueHandlerFunc func(GetDestinationRequestsQueueParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetDestinationRequestsQueueHandlerFunc) Handle(params GetDestinationRequestsQueueParams) middleware.Responder { + return fn(params) +} + +// GetDestinationRequestsQueueHandler interface for that can handle valid get destination requests queue params +type GetDestinationRequestsQueueHandler interface { + Handle(GetDestinationRequestsQueueParams) middleware.Responder +} + +// NewGetDestinationRequestsQueue creates a new http.Handler for the get destination requests queue operation +func NewGetDestinationRequestsQueue(ctx *middleware.Context, handler GetDestinationRequestsQueueHandler) *GetDestinationRequestsQueue { + return &GetDestinationRequestsQueue{Context: ctx, Handler: handler} +} + +/* + GetDestinationRequestsQueue swagger:route GET /queues/destination-requests queues getDestinationRequestsQueue + +Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests) + +A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved. +*/ +type GetDestinationRequestsQueue struct { + Context *middleware.Context + Handler GetDestinationRequestsQueueHandler +} + +func (o *GetDestinationRequestsQueue) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetDestinationRequestsQueueParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go new file mode 100644 index 00000000000..69171c50aed --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go @@ -0,0 +1,644 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// NewGetDestinationRequestsQueueParams creates a new GetDestinationRequestsQueueParams object +// +// There are no default values defined in the spec. +func NewGetDestinationRequestsQueueParams() GetDestinationRequestsQueueParams { + + return GetDestinationRequestsQueueParams{} +} + +// GetDestinationRequestsQueueParams contains all the bound params for the get destination requests queue operation +// typically these are obtained from a http.Request +// +// swagger:parameters getDestinationRequestsQueue +type GetDestinationRequestsQueueParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: query + */ + AppearedInTooAt *strfmt.DateTime + /*Used to illustrate which user is assigned to this move. + + In: query + */ + AssignedTo *string + /* + In: query + */ + Branch *string + /*filters using a counselingOffice name of the move + In: query + */ + CounselingOffice *string + /* + In: query + */ + CustomerName *string + /* + In: query + */ + DestinationDutyLocation *string + /* + In: query + */ + Edipi *string + /* + In: query + */ + Emplid *string + /* + In: query + */ + Locator *string + /*direction of sort order if applied + In: query + */ + Order *string + /*order type + In: query + */ + OrderType *string + /* + Unique: true + In: query + Collection Format: multi + */ + OriginDutyLocation []string + /*requested page of results + In: query + */ + Page *int64 + /*results per page + In: query + */ + PerPage *int64 + /*filters the requested pickup date of a shipment on the move + In: query + */ + RequestedMoveDate *string + /*field that results should be sorted by + In: query + */ + Sort *string + /*Filtering for the status. + Unique: true + In: query + */ + Status []string + /*Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role. + + In: query + */ + ViewAsGBLOC *string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetDestinationRequestsQueueParams() beforehand. +func (o *GetDestinationRequestsQueueParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + qs := runtime.Values(r.URL.Query()) + + qAppearedInTooAt, qhkAppearedInTooAt, _ := qs.GetOK("appearedInTooAt") + if err := o.bindAppearedInTooAt(qAppearedInTooAt, qhkAppearedInTooAt, route.Formats); err != nil { + res = append(res, err) + } + + qAssignedTo, qhkAssignedTo, _ := qs.GetOK("assignedTo") + if err := o.bindAssignedTo(qAssignedTo, qhkAssignedTo, route.Formats); err != nil { + res = append(res, err) + } + + qBranch, qhkBranch, _ := qs.GetOK("branch") + if err := o.bindBranch(qBranch, qhkBranch, route.Formats); err != nil { + res = append(res, err) + } + + qCounselingOffice, qhkCounselingOffice, _ := qs.GetOK("counselingOffice") + if err := o.bindCounselingOffice(qCounselingOffice, qhkCounselingOffice, route.Formats); err != nil { + res = append(res, err) + } + + qCustomerName, qhkCustomerName, _ := qs.GetOK("customerName") + if err := o.bindCustomerName(qCustomerName, qhkCustomerName, route.Formats); err != nil { + res = append(res, err) + } + + qDestinationDutyLocation, qhkDestinationDutyLocation, _ := qs.GetOK("destinationDutyLocation") + if err := o.bindDestinationDutyLocation(qDestinationDutyLocation, qhkDestinationDutyLocation, route.Formats); err != nil { + res = append(res, err) + } + + qEdipi, qhkEdipi, _ := qs.GetOK("edipi") + if err := o.bindEdipi(qEdipi, qhkEdipi, route.Formats); err != nil { + res = append(res, err) + } + + qEmplid, qhkEmplid, _ := qs.GetOK("emplid") + if err := o.bindEmplid(qEmplid, qhkEmplid, route.Formats); err != nil { + res = append(res, err) + } + + qLocator, qhkLocator, _ := qs.GetOK("locator") + if err := o.bindLocator(qLocator, qhkLocator, route.Formats); err != nil { + res = append(res, err) + } + + qOrder, qhkOrder, _ := qs.GetOK("order") + if err := o.bindOrder(qOrder, qhkOrder, route.Formats); err != nil { + res = append(res, err) + } + + qOrderType, qhkOrderType, _ := qs.GetOK("orderType") + if err := o.bindOrderType(qOrderType, qhkOrderType, route.Formats); err != nil { + res = append(res, err) + } + + qOriginDutyLocation, qhkOriginDutyLocation, _ := qs.GetOK("originDutyLocation") + if err := o.bindOriginDutyLocation(qOriginDutyLocation, qhkOriginDutyLocation, route.Formats); err != nil { + res = append(res, err) + } + + qPage, qhkPage, _ := qs.GetOK("page") + if err := o.bindPage(qPage, qhkPage, route.Formats); err != nil { + res = append(res, err) + } + + qPerPage, qhkPerPage, _ := qs.GetOK("perPage") + if err := o.bindPerPage(qPerPage, qhkPerPage, route.Formats); err != nil { + res = append(res, err) + } + + qRequestedMoveDate, qhkRequestedMoveDate, _ := qs.GetOK("requestedMoveDate") + if err := o.bindRequestedMoveDate(qRequestedMoveDate, qhkRequestedMoveDate, route.Formats); err != nil { + res = append(res, err) + } + + qSort, qhkSort, _ := qs.GetOK("sort") + if err := o.bindSort(qSort, qhkSort, route.Formats); err != nil { + res = append(res, err) + } + + qStatus, qhkStatus, _ := qs.GetOK("status") + if err := o.bindStatus(qStatus, qhkStatus, route.Formats); err != nil { + res = append(res, err) + } + + qViewAsGBLOC, qhkViewAsGBLOC, _ := qs.GetOK("viewAsGBLOC") + if err := o.bindViewAsGBLOC(qViewAsGBLOC, qhkViewAsGBLOC, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindAppearedInTooAt binds and validates parameter AppearedInTooAt from query. +func (o *GetDestinationRequestsQueueParams) bindAppearedInTooAt(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + // Format: date-time + value, err := formats.Parse("date-time", raw) + if err != nil { + return errors.InvalidType("appearedInTooAt", "query", "strfmt.DateTime", raw) + } + o.AppearedInTooAt = (value.(*strfmt.DateTime)) + + if err := o.validateAppearedInTooAt(formats); err != nil { + return err + } + + return nil +} + +// validateAppearedInTooAt carries on validations for parameter AppearedInTooAt +func (o *GetDestinationRequestsQueueParams) validateAppearedInTooAt(formats strfmt.Registry) error { + + if err := validate.FormatOf("appearedInTooAt", "query", "date-time", o.AppearedInTooAt.String(), formats); err != nil { + return err + } + return nil +} + +// bindAssignedTo binds and validates parameter AssignedTo from query. +func (o *GetDestinationRequestsQueueParams) bindAssignedTo(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.AssignedTo = &raw + + return nil +} + +// bindBranch binds and validates parameter Branch from query. +func (o *GetDestinationRequestsQueueParams) bindBranch(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Branch = &raw + + return nil +} + +// bindCounselingOffice binds and validates parameter CounselingOffice from query. +func (o *GetDestinationRequestsQueueParams) bindCounselingOffice(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.CounselingOffice = &raw + + return nil +} + +// bindCustomerName binds and validates parameter CustomerName from query. +func (o *GetDestinationRequestsQueueParams) bindCustomerName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.CustomerName = &raw + + return nil +} + +// bindDestinationDutyLocation binds and validates parameter DestinationDutyLocation from query. +func (o *GetDestinationRequestsQueueParams) bindDestinationDutyLocation(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.DestinationDutyLocation = &raw + + return nil +} + +// bindEdipi binds and validates parameter Edipi from query. +func (o *GetDestinationRequestsQueueParams) bindEdipi(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Edipi = &raw + + return nil +} + +// bindEmplid binds and validates parameter Emplid from query. +func (o *GetDestinationRequestsQueueParams) bindEmplid(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Emplid = &raw + + return nil +} + +// bindLocator binds and validates parameter Locator from query. +func (o *GetDestinationRequestsQueueParams) bindLocator(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Locator = &raw + + return nil +} + +// bindOrder binds and validates parameter Order from query. +func (o *GetDestinationRequestsQueueParams) bindOrder(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Order = &raw + + if err := o.validateOrder(formats); err != nil { + return err + } + + return nil +} + +// validateOrder carries on validations for parameter Order +func (o *GetDestinationRequestsQueueParams) validateOrder(formats strfmt.Registry) error { + + if err := validate.EnumCase("order", "query", *o.Order, []interface{}{"asc", "desc"}, true); err != nil { + return err + } + + return nil +} + +// bindOrderType binds and validates parameter OrderType from query. +func (o *GetDestinationRequestsQueueParams) bindOrderType(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.OrderType = &raw + + return nil +} + +// bindOriginDutyLocation binds and validates array parameter OriginDutyLocation from query. +// +// Arrays are parsed according to CollectionFormat: "multi" (defaults to "csv" when empty). +func (o *GetDestinationRequestsQueueParams) bindOriginDutyLocation(rawData []string, hasKey bool, formats strfmt.Registry) error { + // CollectionFormat: multi + originDutyLocationIC := rawData + if len(originDutyLocationIC) == 0 { + return nil + } + + var originDutyLocationIR []string + for _, originDutyLocationIV := range originDutyLocationIC { + originDutyLocationI := originDutyLocationIV + + originDutyLocationIR = append(originDutyLocationIR, originDutyLocationI) + } + + o.OriginDutyLocation = originDutyLocationIR + if err := o.validateOriginDutyLocation(formats); err != nil { + return err + } + + return nil +} + +// validateOriginDutyLocation carries on validations for parameter OriginDutyLocation +func (o *GetDestinationRequestsQueueParams) validateOriginDutyLocation(formats strfmt.Registry) error { + + // uniqueItems: true + if err := validate.UniqueItems("originDutyLocation", "query", o.OriginDutyLocation); err != nil { + return err + } + return nil +} + +// bindPage binds and validates parameter Page from query. +func (o *GetDestinationRequestsQueueParams) bindPage(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + value, err := swag.ConvertInt64(raw) + if err != nil { + return errors.InvalidType("page", "query", "int64", raw) + } + o.Page = &value + + return nil +} + +// bindPerPage binds and validates parameter PerPage from query. +func (o *GetDestinationRequestsQueueParams) bindPerPage(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + + value, err := swag.ConvertInt64(raw) + if err != nil { + return errors.InvalidType("perPage", "query", "int64", raw) + } + o.PerPage = &value + + return nil +} + +// bindRequestedMoveDate binds and validates parameter RequestedMoveDate from query. +func (o *GetDestinationRequestsQueueParams) bindRequestedMoveDate(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.RequestedMoveDate = &raw + + return nil +} + +// bindSort binds and validates parameter Sort from query. +func (o *GetDestinationRequestsQueueParams) bindSort(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.Sort = &raw + + if err := o.validateSort(formats); err != nil { + return err + } + + return nil +} + +// validateSort carries on validations for parameter Sort +func (o *GetDestinationRequestsQueueParams) validateSort(formats strfmt.Registry) error { + + if err := validate.EnumCase("sort", "query", *o.Sort, []interface{}{"customerName", "edipi", "emplid", "branch", "locator", "status", "originDutyLocation", "destinationDutyLocation", "requestedMoveDate", "appearedInTooAt", "assignedTo", "counselingOffice"}, true); err != nil { + return err + } + + return nil +} + +// bindStatus binds and validates array parameter Status from query. +// +// Arrays are parsed according to CollectionFormat: "" (defaults to "csv" when empty). +func (o *GetDestinationRequestsQueueParams) bindStatus(rawData []string, hasKey bool, formats strfmt.Registry) error { + var qvStatus string + if len(rawData) > 0 { + qvStatus = rawData[len(rawData)-1] + } + + // CollectionFormat: + statusIC := swag.SplitByFormat(qvStatus, "") + if len(statusIC) == 0 { + return nil + } + + var statusIR []string + for i, statusIV := range statusIC { + statusI := statusIV + + if err := validate.EnumCase(fmt.Sprintf("%s.%v", "status", i), "query", statusI, []interface{}{"APPROVALS REQUESTED"}, true); err != nil { + return err + } + + statusIR = append(statusIR, statusI) + } + + o.Status = statusIR + if err := o.validateStatus(formats); err != nil { + return err + } + + return nil +} + +// validateStatus carries on validations for parameter Status +func (o *GetDestinationRequestsQueueParams) validateStatus(formats strfmt.Registry) error { + + // uniqueItems: true + if err := validate.UniqueItems("status", "query", o.Status); err != nil { + return err + } + return nil +} + +// bindViewAsGBLOC binds and validates parameter ViewAsGBLOC from query. +func (o *GetDestinationRequestsQueueParams) bindViewAsGBLOC(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + return nil + } + o.ViewAsGBLOC = &raw + + return nil +} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go new file mode 100644 index 00000000000..ea27ea91263 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_responses.go @@ -0,0 +1,149 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/transcom/mymove/pkg/gen/ghcmessages" +) + +// GetDestinationRequestsQueueOKCode is the HTTP code returned for type GetDestinationRequestsQueueOK +const GetDestinationRequestsQueueOKCode int = 200 + +/* +GetDestinationRequestsQueueOK Successfully returned all moves matching the criteria + +swagger:response getDestinationRequestsQueueOK +*/ +type GetDestinationRequestsQueueOK struct { + + /* + In: Body + */ + Payload *ghcmessages.QueueMovesResult `json:"body,omitempty"` +} + +// NewGetDestinationRequestsQueueOK creates GetDestinationRequestsQueueOK with default headers values +func NewGetDestinationRequestsQueueOK() *GetDestinationRequestsQueueOK { + + return &GetDestinationRequestsQueueOK{} +} + +// WithPayload adds the payload to the get destination requests queue o k response +func (o *GetDestinationRequestsQueueOK) WithPayload(payload *ghcmessages.QueueMovesResult) *GetDestinationRequestsQueueOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get destination requests queue o k response +func (o *GetDestinationRequestsQueueOK) SetPayload(payload *ghcmessages.QueueMovesResult) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetDestinationRequestsQueueOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetDestinationRequestsQueueForbiddenCode is the HTTP code returned for type GetDestinationRequestsQueueForbidden +const GetDestinationRequestsQueueForbiddenCode int = 403 + +/* +GetDestinationRequestsQueueForbidden The request was denied + +swagger:response getDestinationRequestsQueueForbidden +*/ +type GetDestinationRequestsQueueForbidden struct { + + /* + In: Body + */ + Payload *ghcmessages.Error `json:"body,omitempty"` +} + +// NewGetDestinationRequestsQueueForbidden creates GetDestinationRequestsQueueForbidden with default headers values +func NewGetDestinationRequestsQueueForbidden() *GetDestinationRequestsQueueForbidden { + + return &GetDestinationRequestsQueueForbidden{} +} + +// WithPayload adds the payload to the get destination requests queue forbidden response +func (o *GetDestinationRequestsQueueForbidden) WithPayload(payload *ghcmessages.Error) *GetDestinationRequestsQueueForbidden { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get destination requests queue forbidden response +func (o *GetDestinationRequestsQueueForbidden) SetPayload(payload *ghcmessages.Error) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetDestinationRequestsQueueForbidden) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(403) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetDestinationRequestsQueueInternalServerErrorCode is the HTTP code returned for type GetDestinationRequestsQueueInternalServerError +const GetDestinationRequestsQueueInternalServerErrorCode int = 500 + +/* +GetDestinationRequestsQueueInternalServerError A server error occurred + +swagger:response getDestinationRequestsQueueInternalServerError +*/ +type GetDestinationRequestsQueueInternalServerError struct { + + /* + In: Body + */ + Payload *ghcmessages.Error `json:"body,omitempty"` +} + +// NewGetDestinationRequestsQueueInternalServerError creates GetDestinationRequestsQueueInternalServerError with default headers values +func NewGetDestinationRequestsQueueInternalServerError() *GetDestinationRequestsQueueInternalServerError { + + return &GetDestinationRequestsQueueInternalServerError{} +} + +// WithPayload adds the payload to the get destination requests queue internal server error response +func (o *GetDestinationRequestsQueueInternalServerError) WithPayload(payload *ghcmessages.Error) *GetDestinationRequestsQueueInternalServerError { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get destination requests queue internal server error response +func (o *GetDestinationRequestsQueueInternalServerError) SetPayload(payload *ghcmessages.Error) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetDestinationRequestsQueueInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go new file mode 100644 index 00000000000..c267cfe2aa8 --- /dev/null +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go @@ -0,0 +1,274 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package queues + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GetDestinationRequestsQueueURL generates an URL for the get destination requests queue operation +type GetDestinationRequestsQueueURL struct { + AppearedInTooAt *strfmt.DateTime + AssignedTo *string + Branch *string + CounselingOffice *string + CustomerName *string + DestinationDutyLocation *string + Edipi *string + Emplid *string + Locator *string + Order *string + OrderType *string + OriginDutyLocation []string + Page *int64 + PerPage *int64 + RequestedMoveDate *string + Sort *string + Status []string + ViewAsGBLOC *string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetDestinationRequestsQueueURL) WithBasePath(bp string) *GetDestinationRequestsQueueURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetDestinationRequestsQueueURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetDestinationRequestsQueueURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/queues/destination-requests" + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/ghc/v1" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + qs := make(url.Values) + + var appearedInTooAtQ string + if o.AppearedInTooAt != nil { + appearedInTooAtQ = o.AppearedInTooAt.String() + } + if appearedInTooAtQ != "" { + qs.Set("appearedInTooAt", appearedInTooAtQ) + } + + var assignedToQ string + if o.AssignedTo != nil { + assignedToQ = *o.AssignedTo + } + if assignedToQ != "" { + qs.Set("assignedTo", assignedToQ) + } + + var branchQ string + if o.Branch != nil { + branchQ = *o.Branch + } + if branchQ != "" { + qs.Set("branch", branchQ) + } + + var counselingOfficeQ string + if o.CounselingOffice != nil { + counselingOfficeQ = *o.CounselingOffice + } + if counselingOfficeQ != "" { + qs.Set("counselingOffice", counselingOfficeQ) + } + + var customerNameQ string + if o.CustomerName != nil { + customerNameQ = *o.CustomerName + } + if customerNameQ != "" { + qs.Set("customerName", customerNameQ) + } + + var destinationDutyLocationQ string + if o.DestinationDutyLocation != nil { + destinationDutyLocationQ = *o.DestinationDutyLocation + } + if destinationDutyLocationQ != "" { + qs.Set("destinationDutyLocation", destinationDutyLocationQ) + } + + var edipiQ string + if o.Edipi != nil { + edipiQ = *o.Edipi + } + if edipiQ != "" { + qs.Set("edipi", edipiQ) + } + + var emplidQ string + if o.Emplid != nil { + emplidQ = *o.Emplid + } + if emplidQ != "" { + qs.Set("emplid", emplidQ) + } + + var locatorQ string + if o.Locator != nil { + locatorQ = *o.Locator + } + if locatorQ != "" { + qs.Set("locator", locatorQ) + } + + var orderQ string + if o.Order != nil { + orderQ = *o.Order + } + if orderQ != "" { + qs.Set("order", orderQ) + } + + var orderTypeQ string + if o.OrderType != nil { + orderTypeQ = *o.OrderType + } + if orderTypeQ != "" { + qs.Set("orderType", orderTypeQ) + } + + var originDutyLocationIR []string + for _, originDutyLocationI := range o.OriginDutyLocation { + originDutyLocationIS := originDutyLocationI + if originDutyLocationIS != "" { + originDutyLocationIR = append(originDutyLocationIR, originDutyLocationIS) + } + } + + originDutyLocation := swag.JoinByFormat(originDutyLocationIR, "multi") + + for _, qsv := range originDutyLocation { + qs.Add("originDutyLocation", qsv) + } + + var pageQ string + if o.Page != nil { + pageQ = swag.FormatInt64(*o.Page) + } + if pageQ != "" { + qs.Set("page", pageQ) + } + + var perPageQ string + if o.PerPage != nil { + perPageQ = swag.FormatInt64(*o.PerPage) + } + if perPageQ != "" { + qs.Set("perPage", perPageQ) + } + + var requestedMoveDateQ string + if o.RequestedMoveDate != nil { + requestedMoveDateQ = *o.RequestedMoveDate + } + if requestedMoveDateQ != "" { + qs.Set("requestedMoveDate", requestedMoveDateQ) + } + + var sortQ string + if o.Sort != nil { + sortQ = *o.Sort + } + if sortQ != "" { + qs.Set("sort", sortQ) + } + + var statusIR []string + for _, statusI := range o.Status { + statusIS := statusI + if statusIS != "" { + statusIR = append(statusIR, statusIS) + } + } + + status := swag.JoinByFormat(statusIR, "") + + if len(status) > 0 { + qsv := status[0] + if qsv != "" { + qs.Set("status", qsv) + } + } + + var viewAsGBLOCQ string + if o.ViewAsGBLOC != nil { + viewAsGBLOCQ = *o.ViewAsGBLOC + } + if viewAsGBLOCQ != "" { + qs.Set("viewAsGBLOC", viewAsGBLOCQ) + } + + _result.RawQuery = qs.Encode() + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetDestinationRequestsQueueURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetDestinationRequestsQueueURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetDestinationRequestsQueueURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetDestinationRequestsQueueURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetDestinationRequestsQueueURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetDestinationRequestsQueueURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go index 38ea0a31b64..9c5d287fab8 100644 --- a/pkg/handlers/ghcapi/api.go +++ b/pkg/handlers/ghcapi/api.go @@ -548,6 +548,13 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI { officeusercreator.NewOfficeUserFetcherPop(), } + ghcAPI.QueuesGetDestinationRequestsQueueHandler = GetDestinationRequestsQueueHandler{ + handlerConfig, + order.NewOrderFetcher(), + movelocker.NewMoveUnlocker(), + officeusercreator.NewOfficeUserFetcherPop(), + } + ghcAPI.QueuesListPrimeMovesHandler = ListPrimeMovesHandler{ handlerConfig, movetaskorder.NewMoveTaskOrderFetcher(), diff --git a/pkg/handlers/ghcapi/queues.go b/pkg/handlers/ghcapi/queues.go index ed4980df650..ab48a061fc1 100644 --- a/pkg/handlers/ghcapi/queues.go +++ b/pkg/handlers/ghcapi/queues.go @@ -178,6 +178,132 @@ func (h GetMovesQueueHandler) Handle(params queues.GetMovesQueueParams) middlewa }) } +// GetDestinationRequestsQueueHandler returns the moves for the TOO queue user via GET /queues/destination-requests +type GetDestinationRequestsQueueHandler struct { + handlers.HandlerConfig + services.OrderFetcher + services.MoveUnlocker + services.OfficeUserFetcherPop +} + +// Handle returns the paginated list of moves with destination requests for a TOO user +func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationRequestsQueueParams) middleware.Responder { + return h.AuditableAppContextFromRequestWithErrors(params.HTTPRequest, + func(appCtx appcontext.AppContext) (middleware.Responder, error) { + if !appCtx.Session().IsOfficeUser() || + (!appCtx.Session().Roles.HasRole(roles.RoleTypeTOO) && !appCtx.Session().Roles.HasRole(roles.RoleTypeHQ)) { + forbiddenErr := apperror.NewForbiddenError( + "user is not authenticated with TOO or HQ office role", + ) + appCtx.Logger().Error(forbiddenErr.Error()) + return queues.NewGetDestinationRequestsQueueForbidden(), forbiddenErr + } + + ListOrderParams := services.ListOrderParams{ + Branch: params.Branch, + Locator: params.Locator, + Edipi: params.Edipi, + Emplid: params.Emplid, + CustomerName: params.CustomerName, + DestinationDutyLocation: params.DestinationDutyLocation, + OriginDutyLocation: params.OriginDutyLocation, + AppearedInTOOAt: handlers.FmtDateTimePtrToPopPtr(params.AppearedInTooAt), + RequestedMoveDate: params.RequestedMoveDate, + Status: params.Status, + Page: params.Page, + PerPage: params.PerPage, + Sort: params.Sort, + Order: params.Order, + OrderType: params.OrderType, + TOOAssignedUser: params.AssignedTo, + CounselingOffice: params.CounselingOffice, + } + + if params.Status == nil { + ListOrderParams.Status = []string{string(models.MoveStatusAPPROVALSREQUESTED)} + } + + // Let's set default values for page and perPage if we don't get arguments for them. We'll use 1 for page and 20 for perPage. + if params.Page == nil { + ListOrderParams.Page = models.Int64Pointer(1) + } + // Same for perPage + if params.PerPage == nil { + ListOrderParams.PerPage = models.Int64Pointer(20) + } + + if params.ViewAsGBLOC != nil && appCtx.Session().Roles.HasRole(roles.RoleTypeHQ) { + ListOrderParams.ViewAsGBLOC = params.ViewAsGBLOC + } + + moves, count, err := h.OrderFetcher.ListDestinationRequestsOrders( + appCtx, + appCtx.Session().OfficeUserID, + roles.RoleTypeTOO, + &ListOrderParams, + ) + if err != nil { + appCtx.Logger(). + Error("error fetching list of moves for office user", zap.Error(err)) + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + + var officeUser models.OfficeUser + if appCtx.Session().OfficeUserID != uuid.Nil { + officeUser, err = h.OfficeUserFetcherPop.FetchOfficeUserByID(appCtx, appCtx.Session().OfficeUserID) + if err != nil { + appCtx.Logger().Error("Error retrieving office user", zap.Error(err)) + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + } + privileges, err := models.FetchPrivilegesForUser(appCtx.DB(), appCtx.Session().UserID) + if err != nil { + appCtx.Logger().Error("Error retreiving user privileges", zap.Error(err)) + } + officeUser.User.Privileges = privileges + officeUser.User.Roles = appCtx.Session().Roles + + if err != nil { + appCtx.Logger(). + Error("error fetching office users", zap.Error(err)) + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + + // if the TOO/office user is accessing the queue, we need to unlock move/moves they have locked + if appCtx.Session().IsOfficeUser() { + officeUserID := appCtx.Session().OfficeUserID + for i, move := range moves { + lockedOfficeUserID := move.LockedByOfficeUserID + if lockedOfficeUserID != nil && *lockedOfficeUserID == officeUserID { + copyOfMove := move + unlockedMove, err := h.UnlockMove(appCtx, ©OfMove, officeUserID) + if err != nil { + return queues.NewGetDestinationRequestsQueueInternalServerError(), err + } + moves[i] = *unlockedMove + } + } + // checking if moves that are NOT in their queue are locked by the user (using search, etc) + err := h.CheckForLockedMovesAndUnlock(appCtx, officeUserID) + if err != nil { + appCtx.Logger().Error(fmt.Sprintf("failed to unlock moves for office user ID: %s", officeUserID), zap.Error(err)) + } + } + + officeUsers := models.OfficeUsers{officeUser} + queueMoves := payloads.QueueMoves(moves, officeUsers, nil, officeUser, nil) + + result := &ghcmessages.QueueMovesResult{ + Page: *ListOrderParams.Page, + PerPage: *ListOrderParams.PerPage, + TotalCount: int64(count), + QueueMoves: *queueMoves, + } + + return queues.NewGetDestinationRequestsQueueOK().WithPayload(result), nil + }) +} + // ListMovesHandler lists moves with the option to filter since a particular date. Optimized ver. type ListPrimeMovesHandler struct { handlers.HandlerConfig diff --git a/pkg/services/mocks/OrderFetcher.go b/pkg/services/mocks/OrderFetcher.go index c7eb39d01ce..012df5ccb1b 100644 --- a/pkg/services/mocks/OrderFetcher.go +++ b/pkg/services/mocks/OrderFetcher.go @@ -80,6 +80,43 @@ func (_m *OrderFetcher) ListAllOrderLocations(appCtx appcontext.AppContext, offi return r0, r1 } +// ListDestinationRequestsOrders provides a mock function with given fields: appCtx, officeUserID, role, params +func (_m *OrderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { + ret := _m.Called(appCtx, officeUserID, role, params) + + if len(ret) == 0 { + panic("no return value specified for ListDestinationRequestsOrders") + } + + var r0 []models.Move + var r1 int + var r2 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) ([]models.Move, int, error)); ok { + return rf(appCtx, officeUserID, role, params) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) []models.Move); ok { + r0 = rf(appCtx, officeUserID, role, params) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.Move) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) int); ok { + r1 = rf(appCtx, officeUserID, role, params) + } else { + r1 = ret.Get(1).(int) + } + + if rf, ok := ret.Get(2).(func(appcontext.AppContext, uuid.UUID, roles.RoleType, *services.ListOrderParams) error); ok { + r2 = rf(appCtx, officeUserID, role, params) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // ListOrders provides a mock function with given fields: appCtx, officeUserID, role, params func (_m *OrderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { ret := _m.Called(appCtx, officeUserID, role, params) diff --git a/pkg/services/order.go b/pkg/services/order.go index c1bd25d1b84..217f3e069f2 100644 --- a/pkg/services/order.go +++ b/pkg/services/order.go @@ -20,6 +20,7 @@ import ( type OrderFetcher interface { FetchOrder(appCtx appcontext.AppContext, orderID uuid.UUID) (*models.Order, error) ListOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *ListOrderParams) ([]models.Move, int, error) + ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *ListOrderParams) ([]models.Move, int, error) ListAllOrderLocations(appCtx appcontext.AppContext, officeUserID uuid.UUID, params *ListOrderParams) ([]models.Move, error) } diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index 9e1c438883a..cfbcebfec0d 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -306,7 +306,153 @@ func (f orderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid return moves, count, nil } -// TODO: Update query to select distinct duty locations +func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { + var moves []models.Move + + var officeUserGbloc string + if params.ViewAsGBLOC != nil { + officeUserGbloc = *params.ViewAsGBLOC + } else { + var gblocErr error + gblocFetcher := officeuser.NewOfficeUserGblocFetcher() + officeUserGbloc, gblocErr = gblocFetcher.FetchGblocForOfficeUser(appCtx, officeUserID) + if gblocErr != nil { + return []models.Move{}, 0, gblocErr + } + } + + ppmCloseoutGblocs := officeUserGbloc == "NAVY" || officeUserGbloc == "TVCB" || officeUserGbloc == "USCG" + + branchQuery := branchFilter(params.Branch, false, ppmCloseoutGblocs) + + // If the user is associated with the USMC GBLOC we want to show them ALL the USMC moves, so let's override here. + // We also only want to do the gbloc filtering thing if we aren't a USMC user, which we cover with the else. + // var gblocQuery QueryOption + var gblocToFilterBy *string + if officeUserGbloc == "USMC" { + branchQuery = branchFilter(models.StringPointer(string(models.AffiliationMARINES)), false, ppmCloseoutGblocs) + gblocToFilterBy = params.OriginGBLOC + } else { + gblocToFilterBy = &officeUserGbloc + } + + gblocQuery := gblocFilterForTOO(gblocToFilterBy) + + locatorQuery := locatorFilter(params.Locator) + dodIDQuery := dodIDFilter(params.Edipi) + emplidQuery := emplidFilter(params.Emplid) + customerNameQuery := customerNameFilter(params.CustomerName) + originDutyLocationQuery := originDutyLocationFilter(params.OriginDutyLocation) + destinationDutyLocationQuery := destinationDutyLocationFilter(params.DestinationDutyLocation) + moveStatusQuery := moveStatusFilter(params.Status) + submittedAtQuery := submittedAtFilter(params.SubmittedAt) + appearedInTOOAtQuery := appearedInTOOAtFilter(params.AppearedInTOOAt) + requestedMoveDateQuery := requestedMoveDateFilter(params.RequestedMoveDate) + closeoutInitiatedQuery := closeoutInitiatedFilter(params.CloseoutInitiated) + closeoutLocationQuery := closeoutLocationFilter(params.CloseoutLocation, ppmCloseoutGblocs) + ppmTypeQuery := ppmTypeFilter(params.PPMType) + ppmStatusQuery := ppmStatusFilter(params.PPMStatus) + scAssignedUserQuery := scAssignedUserFilter(params.SCAssignedUser) + tooAssignedUserQuery := tooAssignedUserFilter(params.TOOAssignedUser) + sortOrderQuery := sortOrder(params.Sort, params.Order, ppmCloseoutGblocs) + counselingQuery := counselingOfficeFilter(params.CounselingOffice) + + // Adding to an array so we can iterate over them and apply the filters after the query structure is set below + options := [20]QueryOption{branchQuery, locatorQuery, dodIDQuery, emplidQuery, customerNameQuery, originDutyLocationQuery, destinationDutyLocationQuery, moveStatusQuery, gblocQuery, submittedAtQuery, appearedInTOOAtQuery, requestedMoveDateQuery, ppmTypeQuery, closeoutInitiatedQuery, closeoutLocationQuery, ppmStatusQuery, sortOrderQuery, scAssignedUserQuery, tooAssignedUserQuery, counselingQuery} + + // we want to set the query up to where it only shows moves that have orders.destination_gbloc that are in the office user's GBLOC (some exclusions apply) + query := appCtx.DB().Q().Scope(utilities.ExcludeDeletedScope(models.MTOShipment{})).EagerPreload( + "Orders.ServiceMember", + "Orders.NewDutyLocation.Address", + "Orders.OriginDutyLocation.Address", + "Orders.Entitlement", + "MTOShipments.DeliveryAddressUpdate", + "MTOServiceItems.ReService.Code", + "ShipmentGBLOC", + "MTOShipments.PPMShipment", + "CloseoutOffice", + "LockedByOfficeUser", + "CounselingOffice", + "SCAssignedUser", + "TOOAssignedUser", + ).InnerJoin("orders", "orders.id = moves.orders_id"). + InnerJoin("service_members", "orders.service_member_id = service_members.id"). + InnerJoin("mto_shipments", "moves.id = mto_shipments.move_id"). + InnerJoin("mto_service_items", "mto_shipments.id = mto_service_items.mto_shipment_id"). + InnerJoin("re_services", "mto_service_items.re_service_id = re_services.id"). + InnerJoin("duty_locations as origin_dl", "orders.origin_duty_location_id = origin_dl.id"). + LeftJoin("transportation_offices as origin_to", "origin_dl.transportation_office_id = origin_to.id"). + LeftJoin("move_to_gbloc", "move_to_gbloc.move_id = moves.id"). + LeftJoin("duty_locations as dest_dl", "dest_dl.id = orders.new_duty_location_id"). + LeftJoin("office_users", "office_users.id = moves.locked_by"). + LeftJoin("transportation_offices", "moves.counseling_transportation_office_id = transportation_offices.id"). + LeftJoin("office_users as assigned_user", "moves.too_assigned_id = assigned_user.id"). + LeftJoin("ppm_shipments", "ppm_shipments.shipment_id = mto_shipments.id"). + LeftJoin("shipment_address_updates", "shipment_address_updates.shipment_id = mto_shipments.id"). + Where("moves.status = 'APPROVALS REQUESTED' "+ + "AND mto_service_items.status = 'SUBMITTED' "+ + "AND re_services.code IN ('DDFSIT', 'DDASIT', 'DDDSIT', 'DDSHUT', 'DDSFSC') "+ + "OR shipment_address_updates.status = 'REQUESTED'"). + Where("orders.destination_gbloc = ?", officeUserGbloc). + Where("moves.show = ?", models.BoolPointer(true)) + + for _, option := range options { + if option != nil { + option(query) + } + } + + // Pass zeros into paginate in this case. Which will give us 1 page and 20 per page respectively + if params.Page == nil { + params.Page = models.Int64Pointer(0) + } + if params.PerPage == nil { + params.PerPage = models.Int64Pointer(0) + } + + var groupByColumms []string + groupByColumms = append(groupByColumms, "service_members.id", "orders.id", "origin_dl.id") + + if params.Sort != nil && *params.Sort == "originDutyLocation" { + groupByColumms = append(groupByColumms, "origin_dl.name") + } + if params.Sort != nil && *params.Sort == "destinationDutyLocation" { + groupByColumms = append(groupByColumms, "dest_dl.name") + } + if params.Sort != nil && *params.Sort == "originGBLOC" { + groupByColumms = append(groupByColumms, "origin_to.id") + } + if params.Sort != nil && *params.Sort == "counselingOffice" { + groupByColumms = append(groupByColumms, "transportation_offices.id") + } + if params.Sort != nil && *params.Sort == "assignedTo" { + groupByColumms = append(groupByColumms, "assigned_user.last_name", "assigned_user.first_name") + } + + err := query.GroupBy("moves.id", groupByColumms...).Paginate(int(*params.Page), int(*params.PerPage)).All(&moves) + if err != nil { + return []models.Move{}, 0, err + } + + count := query.Paginator.TotalEntriesSize + + for i := range moves { + if moves[i].Orders.OriginDutyLocation != nil { + loadErr := appCtx.DB().Load(moves[i].Orders.OriginDutyLocation, "TransportationOffice") + if loadErr != nil { + return []models.Move{}, 0, err + } + } + + err := appCtx.DB().Load(&moves[i].Orders.ServiceMember, "BackupContacts") + if err != nil { + return []models.Move{}, 0, err + } + } + + return moves, count, nil +} + func (f orderFetcher) ListAllOrderLocations(appCtx appcontext.AppContext, officeUserID uuid.UUID, params *services.ListOrderParams) ([]models.Move, error) { var moves []models.Move var err error diff --git a/src/constants/routes.js b/src/constants/routes.js index 1c4121aef59..a018cef31ea 100644 --- a/src/constants/routes.js +++ b/src/constants/routes.js @@ -4,8 +4,8 @@ export const generalRoutes = { REQUEST_ACCOUNT: '/request-account', PRIVACY_SECURITY_POLICY_PATH: '/privacy-and-security-policy', ACCESSIBILITY_PATH: '/accessibility', - QUEUE_SEARCH_PATH: 'Search', - BASE_QUEUE_SEARCH_PATH: '/Search', + QUEUE_SEARCH_PATH: 'search', + BASE_QUEUE_SEARCH_PATH: '/search', }; export const customerRoutes = { @@ -120,6 +120,8 @@ export const tooRoutes = { BASE_SHIPMENT_EDIT_PATH: `${BASE_MOVES_PATH}/shipments/:shipmentId`, MOVE_QUEUE: `move-queue`, BASE_MOVE_QUEUE: `/move-queue`, + BASE_DESTINATION_REQUESTS_QUEUE: `/destination-requests`, + DESTINATION_REQUESTS_QUEUE: `destination-requests`, SHIPMENT_EDIT_PATH: 'shipments/:shipmentId', BASE_MOVE_VIEW_PATH: `${BASE_MOVES_PATH}/details`, MOVE_VIEW_PATH: 'details', diff --git a/src/hooks/queries.js b/src/hooks/queries.js index ce469702359..749f7602a91 100644 --- a/src/hooks/queries.js +++ b/src/hooks/queries.js @@ -34,6 +34,7 @@ import { getPPMActualWeight, searchCustomers, getGBLOCs, + getDestinationRequestsQueue, getBulkAssignmentData, } from 'services/ghcApi'; import { getLoggedInUserQueries } from 'services/internalApi'; @@ -586,6 +587,28 @@ export const useMovesQueueQueries = ({ }; }; +export const useDestinationRequestsQueueQueries = ({ + sort, + order, + filters = [], + currentPage = PAGINATION_PAGE_DEFAULT, + currentPageSize = PAGINATION_PAGE_SIZE_DEFAULT, + viewAsGBLOC, +}) => { + const { data = {}, ...movesQueueQuery } = useQuery( + [MOVES_QUEUE, { sort, order, filters, currentPage, currentPageSize, viewAsGBLOC }], + ({ queryKey }) => getDestinationRequestsQueue(...queryKey), + ); + const { isLoading, isError, isSuccess } = movesQueueQuery; + const { queueMoves, ...dataProps } = data; + return { + queueResult: { data: queueMoves, ...dataProps }, + isLoading, + isError, + isSuccess, + }; +}; + export const useServicesCounselingQueuePPMQueries = ({ sort, order, diff --git a/src/pages/Office/MoveQueue/MoveQueue.jsx b/src/pages/Office/MoveQueue/MoveQueue.jsx index 95b703189fc..e0c08868603 100644 --- a/src/pages/Office/MoveQueue/MoveQueue.jsx +++ b/src/pages/Office/MoveQueue/MoveQueue.jsx @@ -6,8 +6,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import styles from './MoveQueue.module.scss'; import { createHeader } from 'components/Table/utils'; -import { useMovesQueueQueries, useUserQueries, useMoveSearchQueries } from 'hooks/queries'; -import { getMovesQueue } from 'services/ghcApi'; +import { + useMovesQueueQueries, + useUserQueries, + useMoveSearchQueries, + useDestinationRequestsQueueQueries, +} from 'hooks/queries'; +import { getDestinationRequestsQueue, getMovesQueue } from 'services/ghcApi'; import { formatDateFromIso, serviceMemberAgencyLabel } from 'utils/formatters'; import MultiSelectCheckBoxFilter from 'components/Table/Filters/MultiSelectCheckBoxFilter'; import SelectFilter from 'components/Table/Filters/SelectFilter'; @@ -270,6 +275,15 @@ const MoveQueue = ({ isQueueManagementFFEnabled, userPrivileges, isBulkAssignmen Task Order Queue , + (isActive ? 'usa-current' : '')} + to={tooRoutes.BASE_DESTINATION_REQUESTS_QUEUE} + > + + Destination Requests Queue + + , (isActive ? 'usa-current' : '')} @@ -338,6 +352,32 @@ const MoveQueue = ({ isQueueManagementFFEnabled, userPrivileges, isBulkAssignmen ); } + if (queueType === tooRoutes.DESTINATION_REQUESTS_QUEUE) { + return ( +
+ {renderNavBar()} + +
+ ); + } return ; }; diff --git a/src/services/ghcApi.js b/src/services/ghcApi.js index 1b787b7b8ad..d405122099f 100644 --- a/src/services/ghcApi.js +++ b/src/services/ghcApi.js @@ -632,6 +632,22 @@ export async function getMovesQueue( ); } +export async function getDestinationRequestsQueue( + key, + { sort, order, filters = [], currentPage = 1, currentPageSize = 20, viewAsGBLOC }, +) { + const operationPath = 'queues.getDestinationRequestsQueue'; + const paramFilters = {}; + filters.forEach((filter) => { + paramFilters[`${filter.id}`] = filter.value; + }); + return makeGHCRequest( + operationPath, + { sort, order, page: currentPage, perPage: currentPageSize, viewAsGBLOC, ...paramFilters }, + { schemaKey: 'queueMovesResult', normalize: false }, + ); +} + export async function getServicesCounselingQueue( key, { sort, order, filters = [], currentPage = 1, currentPageSize = 20, needsPPMCloseout = false, viewAsGBLOC }, diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index df06a4ca220..63f6083a887 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -3735,6 +3735,118 @@ paths: $ref: '#/responses/PermissionDenied' '500': $ref: '#/responses/ServerError' + /queues/destination-requests: + get: + produces: + - application/json + summary: Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests) + description: > + A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved. + operationId: getDestinationRequestsQueue + tags: + - queues + parameters: + - in: query + name: page + type: integer + description: requested page of results + - in: query + name: perPage + type: integer + description: results per page + - in: query + name: sort + type: string + enum: + [ + customerName, + edipi, + emplid, + branch, + locator, + status, + originDutyLocation, + destinationDutyLocation, + requestedMoveDate, + appearedInTooAt, + assignedTo, + counselingOffice, + ] + description: field that results should be sorted by + - in: query + name: order + type: string + enum: [asc, desc] + description: direction of sort order if applied + - in: query + name: branch + type: string + - in: query + name: locator + type: string + - in: query + name: customerName + type: string + - in: query + name: edipi + type: string + - in: query + name: emplid + type: string + - in: query + name: originDutyLocation + type: array + uniqueItems: true + collectionFormat: multi + items: + type: string + - in: query + name: destinationDutyLocation + type: string + - in: query + name: appearedInTooAt + type: string + format: date-time + - in: query + name: requestedMoveDate + type: string + description: filters the requested pickup date of a shipment on the move + - in: query + name: status + type: array + description: Filtering for the status. + uniqueItems: true + items: + type: string + enum: + - APPROVALS REQUESTED + - in: query + name: orderType + type: string + description: order type + - in: query + name: viewAsGBLOC + type: string + description: | + Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role. + - in: query + name: assignedTo + type: string + description: | + Used to illustrate which user is assigned to this move. + - in: query + name: counselingOffice + type: string + description: filters using a counselingOffice name of the move + responses: + '200': + description: Successfully returned all moves matching the criteria + schema: + $ref: '#/definitions/QueueMovesResult' + '403': + $ref: '#/responses/PermissionDenied' + '500': + $ref: '#/responses/ServerError' /queues/payment-requests: get: produces: diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index a92ed3016a6..6df16f2884f 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -3901,6 +3901,125 @@ paths: $ref: '#/responses/PermissionDenied' '500': $ref: '#/responses/ServerError' + /queues/destination-requests: + get: + produces: + - application/json + summary: >- + Gets queued list of all customer moves by GBLOC that have destination + requests (destination SIT, shuttle, address requests) + description: > + A TOO will view this queue when they have destination requests tied to + their GBLOC. This includes unapproved destination SIT service items + (including shuttle) and destination address requests that are not + approved. + operationId: getDestinationRequestsQueue + tags: + - queues + parameters: + - in: query + name: page + type: integer + description: requested page of results + - in: query + name: perPage + type: integer + description: results per page + - in: query + name: sort + type: string + enum: + - customerName + - edipi + - emplid + - branch + - locator + - status + - originDutyLocation + - destinationDutyLocation + - requestedMoveDate + - appearedInTooAt + - assignedTo + - counselingOffice + description: field that results should be sorted by + - in: query + name: order + type: string + enum: + - asc + - desc + description: direction of sort order if applied + - in: query + name: branch + type: string + - in: query + name: locator + type: string + - in: query + name: customerName + type: string + - in: query + name: edipi + type: string + - in: query + name: emplid + type: string + - in: query + name: originDutyLocation + type: array + uniqueItems: true + collectionFormat: multi + items: + type: string + - in: query + name: destinationDutyLocation + type: string + - in: query + name: appearedInTooAt + type: string + format: date-time + - in: query + name: requestedMoveDate + type: string + description: filters the requested pickup date of a shipment on the move + - in: query + name: status + type: array + description: Filtering for the status. + uniqueItems: true + items: + type: string + enum: + - APPROVALS REQUESTED + - in: query + name: orderType + type: string + description: order type + - in: query + name: viewAsGBLOC + type: string + description: > + Used to return a queue for a GBLOC other than the default of the + current user. Requires the HQ role. The parameter is ignored if the + requesting user does not have the necessary role. + - in: query + name: assignedTo + type: string + description: | + Used to illustrate which user is assigned to this move. + - in: query + name: counselingOffice + type: string + description: filters using a counselingOffice name of the move + responses: + '200': + description: Successfully returned all moves matching the criteria + schema: + $ref: '#/definitions/QueueMovesResult' + '403': + $ref: '#/responses/PermissionDenied' + '500': + $ref: '#/responses/ServerError' /queues/payment-requests: get: produces: From 263e5f652927c084f237d56e41e1a9d0f6ebfff0 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Fri, 24 Jan 2025 22:19:34 +0000 Subject: [PATCH 02/21] most of it is working, just need to get clarification on move_to_gblocs, add tests, and refine refine refine --- ...73216_add_destination_queue_db_func.up.sql | 206 +++++++++++++----- pkg/gen/ghcapi/embedded_spec.go | 4 + ...t_destination_requests_queue_parameters.go | 2 +- .../internal/payloads/model_to_payload.go | 2 +- pkg/models/move.go | 6 +- pkg/models/mto_shipments.go | 136 ++++++------ pkg/models/order.go | 4 +- pkg/services/order/order_fetcher.go | 202 ++++++++--------- swagger-def/ghc.yaml | 2 + swagger/ghc.yaml | 2 + 10 files changed, 325 insertions(+), 241 deletions(-) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql index 8808b472e68..f6c40773200 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql @@ -1,64 +1,139 @@ +-- database function that returns a list of moves that have destination requests +-- this includes shipment address update requests & destination service items CREATE OR REPLACE FUNCTION get_destination_queue( - move_code TEXT DEFAULT NULL, -- Search parameter for Move Code - input_move_id UUID DEFAULT NULL, -- Search parameter for Move ID - page INTEGER DEFAULT 1, -- Page number for pagination - per_page INTEGER DEFAULT 20, -- Number of results per page - branch TEXT DEFAULT NULL, -- Filter: service_member.affiliation - edipi TEXT DEFAULT NULL, -- Filter: service_member.edipi - emplid TEXT DEFAULT NULL, -- Filter: service_member.emplid - customer_name TEXT DEFAULT NULL, -- Filter: service_member.first_name + last_name - destination_duty_location TEXT DEFAULT NULL,-- Filter: orders.new_duty_location_id.name - origin_duty_location TEXT DEFAULT NULL, -- Filter: orders.origin_duty_location_id.name - origin_gbloc TEXT DEFAULT NULL, -- Filter: move.counseling_office_transportation_office.gbloc - submitted_at TIMESTAMP DEFAULT NULL, -- Filter: moves.submitted_at - appeared_in_too_at TIMESTAMP DEFAULT NULL, -- Filter: moves.appeared_in_too_at - too_assigned_user TEXT DEFAULT NULL -- Filter: moves.too_assigned_id -> office_users.first_name + last_name + user_gbloc TEXT DEFAULT NULL, + customer_name TEXT DEFAULT NULL, + edipi TEXT DEFAULT NULL, + emplid TEXT DEFAULT NULL, + m_status TEXT[] DEFAULT NULL, + move_code TEXT DEFAULT NULL, + requested_move_date TIMESTAMP DEFAULT NULL, + date_submitted TIMESTAMP DEFAULT NULL, + branch TEXT DEFAULT NULL, + origin_duty_location TEXT DEFAULT NULL, + counseling_office TEXT DEFAULT NULL, + too_assigned_user TEXT DEFAULT NULL, + page INTEGER DEFAULT 1, + per_page INTEGER DEFAULT 20 ) RETURNS TABLE ( - move_id UUID, + id UUID, locator TEXT, + submitted_at TIMESTAMP WITH TIME ZONE, orders_id UUID, - available_to_prime_at TIMESTAMP WITH TIME ZONE, - show BOOLEAN, + status TEXT, + locked_by UUID, + too_assigned_id UUID, + counseling_transportation_office_id UUID, + orders JSONB, + mto_shipments JSONB, + counseling_transportation_office JSONB, + too_assigned JSONB, total_count BIGINT ) AS $$ DECLARE sql_query TEXT; offset_value INTEGER; BEGIN + IF page < 1 THEN + page := 1; + END IF; + + IF per_page < 1 THEN + per_page := 20; + END IF; + -- OFFSET for pagination offset_value := (page - 1) * per_page; sql_query := ' - SELECT moves.id AS move_id, - moves.locator::TEXT AS locator, - moves.orders_id, - moves.available_to_prime_at, - moves.show, - COUNT(*) OVER() AS total_count + SELECT + moves.id AS id, + moves.locator::TEXT AS locator, + moves.submitted_at::TIMESTAMP WITH TIME ZONE AS submitted_at, + moves.orders_id AS orders_id, + moves.status::TEXT AS status, + moves.locked_by AS locked_by, + moves.too_assigned_id AS too_assigned_id, + moves.counseling_transportation_office_id AS counseling_transportation_office_id, + json_build_object( + ''id'', orders.id, + ''origin_duty_location_gbloc'', orders.gbloc, + ''service_member'', json_build_object( + ''id'', service_members.id, + ''first_name'', service_members.first_name, + ''last_name'', service_members.last_name, + ''edipi'', service_members.edipi, + ''emplid'', service_members.emplid, + ''affiliation'', service_members.affiliation + ), + ''origin_duty_location'', json_build_object( + ''name'', origin_duty_locations.name + ) + )::JSONB AS orders, + COALESCE( + json_agg( + json_build_object( + ''id'', mto_shipments.id, + ''shipment_type'', mto_shipments.shipment_type, + ''status'', mto_shipments.status, + ''requested_pickup_date'', TO_CHAR(mto_shipments.requested_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''scheduled_pickup_date'', TO_CHAR(mto_shipments.scheduled_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''requested_delivery_date'', TO_CHAR(mto_shipments.requested_delivery_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''approved_date'', TO_CHAR(mto_shipments.approved_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''prime_estimated_weight'', mto_shipments.prime_estimated_weight + ) + ) FILTER (WHERE mto_shipments.id IS NOT NULL), + ''[]'' + )::JSONB AS mto_shipments, + json_build_object( + ''name'', counseling_offices.name + )::JSONB AS counseling_transportation_office, + json_build_object( + ''first_name'', too_user.first_name, + ''last_name'', too_user.last_name + )::JSONB AS too_assigned, + COUNT(*) OVER() AS total_count FROM moves INNER JOIN orders ON moves.orders_id = orders.id - INNER JOIN service_members ON orders.service_member_id = service_members.id + LEFT JOIN mto_shipments ON mto_shipments.move_id = moves.id + LEFT JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id + LEFT JOIN mto_service_items ON mto_shipments.id = mto_service_items.mto_shipment_id + LEFT JOIN re_services ON mto_service_items.re_service_id = re_services.id + LEFT JOIN service_members ON orders.service_member_id = service_members.id LEFT JOIN duty_locations AS new_duty_locations ON orders.new_duty_location_id = new_duty_locations.id LEFT JOIN duty_locations AS origin_duty_locations ON orders.origin_duty_location_id = origin_duty_locations.id - LEFT JOIN office_users ON moves.too_assigned_id = office_users.id + LEFT JOIN office_users AS too_user ON moves.too_assigned_id = too_user.id + LEFT JOIN office_users AS locked_user ON moves.locked_by = locked_user.id LEFT JOIN transportation_offices AS counseling_offices ON moves.counseling_transportation_office_id = counseling_offices.id - WHERE moves.available_to_prime_at IS NOT NULL - AND moves.show = TRUE + LEFT JOIN shipment_address_updates ON shipment_address_updates.shipment_id = mto_shipments.id + LEFT JOIN move_to_gbloc ON move_to_gbloc.move_id = moves.id + WHERE moves.show = TRUE '; - -- add dynamic filters based on provided parameters - IF move_code IS NOT NULL THEN - sql_query := sql_query || ' AND moves.locator ILIKE ''%' || UPPER(move_code) || '%'' '; - END IF; + -- adding conditionals for destination queue + -- we only want to see moves that have destination requests (shipment address updates, destination service items in SUBMITTED status) + sql_query := sql_query || ' + AND ( + shipment_address_updates.status = ''REQUESTED'' + OR ( + mto_service_items.status = ''SUBMITTED'' + AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSHUT'', ''DDSFSC'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSHUT'') + ) + ) + '; - IF input_move_id IS NOT NULL THEN - sql_query := sql_query || ' AND moves.id = ''' || input_move_id || ''' '; + -- this should always be passed in from the service object, but will nil check it anyway + IF user_gbloc IS NOT NULL THEN + sql_query := sql_query || ' AND move_to_gbloc.gbloc = ''%' || user_gbloc || '%'' '; END IF; - IF branch IS NOT NULL THEN - sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%' || branch || '%'' '; + IF customer_name IS NOT NULL AND customer_name <> '' THEN + sql_query := sql_query || ' AND ( + service_members.first_name || '' '' || service_members.last_name ILIKE ''%' || customer_name || '%'' + OR service_members.last_name || '' '' || service_members.first_name ILIKE ''%' || customer_name || '%'' + ) '; END IF; IF edipi IS NOT NULL THEN @@ -69,38 +144,69 @@ BEGIN sql_query := sql_query || ' AND service_members.emplid ILIKE ''%' || emplid || '%'' '; END IF; - IF customer_name IS NOT NULL THEN - sql_query := sql_query || ' AND (service_members.first_name || '' '' || service_members.last_name) ILIKE ''%' || customer_name || '%'' '; + IF m_status IS NOT NULL THEN + sql_query := sql_query || ' AND moves.status IN (SELECT unnest($1)) '; END IF; - IF destination_duty_location IS NOT NULL THEN - sql_query := sql_query || ' AND new_duty_locations.name ILIKE ''%' || destination_duty_location || '%'' '; + IF move_code IS NOT NULL THEN + sql_query := sql_query || ' AND moves.locator ILIKE ''%' || UPPER(move_code) || '%'' '; END IF; - IF origin_duty_location IS NOT NULL THEN - sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%' || origin_duty_location || '%'' '; + IF requested_move_date IS NOT NULL THEN + sql_query := sql_query || ' AND ( + mto_shipments.requested_pickup_date::DATE = ' || quote_literal(requested_move_date) || '::DATE + OR ppm_shipments.expected_departure_date::DATE = ' || quote_literal(requested_move_date) || '::DATE + OR (mto_shipments.shipment_type = ''HHG_OUTOF_NTS'' AND mto_shipments.requested_delivery_date::DATE = ' || quote_literal(requested_move_date) || '::DATE) + )'; END IF; - IF origin_gbloc IS NOT NULL THEN - sql_query := sql_query || ' AND counseling_offices.gbloc ILIKE ''%' || origin_gbloc || '%'' '; + IF date_submitted IS NOT NULL THEN + sql_query := sql_query || ' AND moves.submitted_at = ' || quote_literal(date_submitted) || ' '; END IF; - IF submitted_at IS NOT NULL THEN - sql_query := sql_query || ' AND moves.submitted_at = ''' || submitted_at || ''' '; + IF branch IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%' || branch || '%'' '; END IF; - IF appeared_in_too_at IS NOT NULL THEN - sql_query := sql_query || ' AND moves.appeared_in_too_at = ''' || appeared_in_too_at || ''' '; + IF origin_duty_location IS NOT NULL AND origin_duty_location <> '' THEN + sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%' || origin_duty_location || '%'' '; + END IF; + + IF counseling_office IS NOT NULL THEN + sql_query := sql_query || ' AND counseling_offices.name ILIKE ''%' || counseling_office || '%'' '; END IF; IF too_assigned_user IS NOT NULL THEN - sql_query := sql_query || ' AND (office_users.first_name || '' '' || office_users.last_name) ILIKE ''%' || too_assigned_user || '%'' '; + sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%' || quote_literal(too_assigned_user) || '%'' '; END IF; + sql_query := sql_query || ' + GROUP BY + moves.id, + moves.locator, + moves.submitted_at, + moves.orders_id, + moves.status, + moves.locked_by, + moves.too_assigned_id, + moves.counseling_transportation_office_id, + orders.id, + service_members.id, + service_members.first_name, + service_members.last_name, + service_members.edipi, + service_members.emplid, + service_members.affiliation, + origin_duty_locations.name, + counseling_offices.name, + too_user.first_name, + too_user.last_name'; sql_query := sql_query || ' ORDER BY moves.id ASC '; sql_query := sql_query || ' LIMIT ' || per_page || ' OFFSET ' || offset_value || ' '; - RETURN QUERY EXECUTE sql_query; + RAISE NOTICE 'Query: %', sql_query; + + RETURN QUERY EXECUTE sql_query USING m_status; END; -$$ LANGUAGE plpgsql; \ No newline at end of file +$$ LANGUAGE plpgsql; diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 878032b252f..cdc4fced512 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -4787,6 +4787,8 @@ func init() { "type": "array", "items": { "enum": [ + "SUBMITTED", + "SERVICE COUNSELING COMPLETED", "APPROVALS REQUESTED" ], "type": "string" @@ -21607,6 +21609,8 @@ func init() { "type": "array", "items": { "enum": [ + "SUBMITTED", + "SERVICE COUNSELING COMPLETED", "APPROVALS REQUESTED" ], "type": "string" diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go index 69171c50aed..86930ef5fab 100644 --- a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go @@ -600,7 +600,7 @@ func (o *GetDestinationRequestsQueueParams) bindStatus(rawData []string, hasKey for i, statusIV := range statusIC { statusI := statusIV - if err := validate.EnumCase(fmt.Sprintf("%s.%v", "status", i), "query", statusI, []interface{}{"APPROVALS REQUESTED"}, true); err != nil { + if err := validate.EnumCase(fmt.Sprintf("%s.%v", "status", i), "query", statusI, []interface{}{"SUBMITTED", "SERVICE COUNSELING COMPLETED", "APPROVALS REQUESTED"}, true); err != nil { return err } diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go index 7c5b503c83a..fd6dec78247 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go @@ -54,7 +54,7 @@ func OfficeUser(officeUser *models.OfficeUser) *ghcmessages.LockedOfficeUser { } func AssignedOfficeUser(officeUser *models.OfficeUser) *ghcmessages.AssignedOfficeUser { - if officeUser != nil { + if officeUser != nil && officeUser.FirstName != "" && officeUser.LastName != "" { payload := ghcmessages.AssignedOfficeUser{ OfficeUserID: strfmt.UUID(officeUser.ID.String()), FirstName: officeUser.FirstName, diff --git a/pkg/models/move.go b/pkg/models/move.go index f0b3ac49269..a8e9a02e8c1 100644 --- a/pkg/models/move.go +++ b/pkg/models/move.go @@ -71,7 +71,7 @@ type Move struct { PPMType *string `db:"ppm_type"` MTOServiceItems MTOServiceItems `has_many:"mto_service_items" fk_id:"move_id"` PaymentRequests PaymentRequests `has_many:"payment_requests" fk_id:"move_id"` - MTOShipments MTOShipments `has_many:"mto_shipments" fk_id:"move_id"` + MTOShipments MTOShipments `json:"mto_shipments" has_many:"mto_shipments" fk_id:"move_id"` ReferenceID *string `db:"reference_id"` ServiceCounselingCompletedAt *time.Time `db:"service_counseling_completed_at"` PrimeCounselingCompletedAt *time.Time `db:"prime_counseling_completed_at"` @@ -98,11 +98,11 @@ type Move struct { SCAssignedID *uuid.UUID `json:"sc_assigned_id" db:"sc_assigned_id"` SCAssignedUser *OfficeUser `belongs_to:"office_users" fk_id:"sc_assigned_id"` TOOAssignedID *uuid.UUID `json:"too_assigned_id" db:"too_assigned_id"` - TOOAssignedUser *OfficeUser `belongs_to:"office_users" fk_id:"too_assigned_id"` + TOOAssignedUser *OfficeUser `json:"too_assigned" belongs_to:"office_users" fk_id:"too_assigned_id"` TIOAssignedID *uuid.UUID `json:"tio_assigned_id" db:"tio_assigned_id"` TIOAssignedUser *OfficeUser `belongs_to:"office_users" fk_id:"tio_assigned_id"` CounselingOfficeID *uuid.UUID `json:"counseling_transportation_office_id" db:"counseling_transportation_office_id"` - CounselingOffice *TransportationOffice `belongs_to:"transportation_offices" fk_id:"counseling_transportation_office_id"` + CounselingOffice *TransportationOffice `json:"counseling_transportation_office" belongs_to:"transportation_offices" fk_id:"counseling_transportation_office_id"` } type MoveWithEarliestDate struct { diff --git a/pkg/models/mto_shipments.go b/pkg/models/mto_shipments.go index 917e75b7978..1b2e6abbc0d 100644 --- a/pkg/models/mto_shipments.go +++ b/pkg/models/mto_shipments.go @@ -101,74 +101,74 @@ const ( // MTOShipment is an object representing data for a move task order shipment type MTOShipment struct { - ID uuid.UUID `db:"id"` - MoveTaskOrder Move `belongs_to:"moves" fk_id:"move_id"` - MoveTaskOrderID uuid.UUID `db:"move_id"` - ScheduledPickupDate *time.Time `db:"scheduled_pickup_date"` - RequestedPickupDate *time.Time `db:"requested_pickup_date"` - RequestedDeliveryDate *time.Time `db:"requested_delivery_date"` - ApprovedDate *time.Time `db:"approved_date"` - FirstAvailableDeliveryDate *time.Time `db:"first_available_delivery_date"` - ActualPickupDate *time.Time `db:"actual_pickup_date"` - RequiredDeliveryDate *time.Time `db:"required_delivery_date"` - ScheduledDeliveryDate *time.Time `db:"scheduled_delivery_date"` - ActualDeliveryDate *time.Time `db:"actual_delivery_date"` - CustomerRemarks *string `db:"customer_remarks"` - CounselorRemarks *string `db:"counselor_remarks"` - PickupAddress *Address `belongs_to:"addresses" fk_id:"pickup_address_id"` - PickupAddressID *uuid.UUID `db:"pickup_address_id"` - DestinationAddress *Address `belongs_to:"addresses" fk_id:"destination_address_id"` - DestinationAddressID *uuid.UUID `db:"destination_address_id"` - DestinationType *DestinationType `db:"destination_address_type"` - MTOAgents MTOAgents `has_many:"mto_agents" fk_id:"mto_shipment_id"` - MTOServiceItems MTOServiceItems `has_many:"mto_service_items" fk_id:"mto_shipment_id"` - SecondaryPickupAddress *Address `belongs_to:"addresses" fk_id:"secondary_pickup_address_id"` - SecondaryPickupAddressID *uuid.UUID `db:"secondary_pickup_address_id"` - HasSecondaryPickupAddress *bool `db:"has_secondary_pickup_address"` - SecondaryDeliveryAddress *Address `belongs_to:"addresses" fk_id:"secondary_delivery_address_id"` - SecondaryDeliveryAddressID *uuid.UUID `db:"secondary_delivery_address_id"` - HasSecondaryDeliveryAddress *bool `db:"has_secondary_delivery_address"` - TertiaryPickupAddress *Address `belongs_to:"addresses" fk_id:"tertiary_pickup_address_id"` - TertiaryPickupAddressID *uuid.UUID `db:"tertiary_pickup_address_id"` - HasTertiaryPickupAddress *bool `db:"has_tertiary_pickup_address"` - TertiaryDeliveryAddress *Address `belongs_to:"addresses" fk_id:"tertiary_delivery_address_id"` - TertiaryDeliveryAddressID *uuid.UUID `db:"tertiary_delivery_address_id"` - HasTertiaryDeliveryAddress *bool `db:"has_tertiary_delivery_address"` - SITDaysAllowance *int `db:"sit_days_allowance"` - SITDurationUpdates SITDurationUpdates `has_many:"sit_extensions" fk_id:"mto_shipment_id"` - PrimeEstimatedWeight *unit.Pound `db:"prime_estimated_weight"` - PrimeEstimatedWeightRecordedDate *time.Time `db:"prime_estimated_weight_recorded_date"` - PrimeActualWeight *unit.Pound `db:"prime_actual_weight"` - BillableWeightCap *unit.Pound `db:"billable_weight_cap"` - BillableWeightJustification *string `db:"billable_weight_justification"` - NTSRecordedWeight *unit.Pound `db:"nts_recorded_weight"` - ShipmentType MTOShipmentType `db:"shipment_type"` - Status MTOShipmentStatus `db:"status"` - Diversion bool `db:"diversion"` - DiversionReason *string `db:"diversion_reason"` - DivertedFromShipmentID *uuid.UUID `db:"diverted_from_shipment_id"` - ActualProGearWeight *unit.Pound `db:"actual_pro_gear_weight"` - ActualSpouseProGearWeight *unit.Pound `db:"actual_spouse_pro_gear_weight"` - RejectionReason *string `db:"rejection_reason"` - Distance *unit.Miles `db:"distance"` - Reweigh *Reweigh `has_one:"reweighs" fk_id:"shipment_id"` - UsesExternalVendor bool `db:"uses_external_vendor"` - StorageFacility *StorageFacility `belongs_to:"storage_facilities" fk:"storage_facility_id"` - StorageFacilityID *uuid.UUID `db:"storage_facility_id"` - ServiceOrderNumber *string `db:"service_order_number"` - TACType *LOAType `db:"tac_type"` - SACType *LOAType `db:"sac_type"` - PPMShipment *PPMShipment `has_one:"ppm_shipment" fk_id:"shipment_id"` - BoatShipment *BoatShipment `has_one:"boat_shipment" fk_id:"shipment_id"` - DeliveryAddressUpdate *ShipmentAddressUpdate `has_one:"shipment_address_update" fk_id:"shipment_id"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - DeletedAt *time.Time `db:"deleted_at"` - ShipmentLocator *string `db:"shipment_locator"` - 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"` + ID uuid.UUID `json:"id" db:"id"` + MoveTaskOrder Move `json:"move_task_order" belongs_to:"moves" fk_id:"move_id"` + MoveTaskOrderID uuid.UUID `json:"move_task_order_id" db:"move_id"` + ScheduledPickupDate *time.Time `json:"scheduled_pickup_date" db:"scheduled_pickup_date"` + RequestedPickupDate *time.Time `json:"requested_pickup_date" db:"requested_pickup_date"` + RequestedDeliveryDate *time.Time `json:"requested_delivery_date" db:"requested_delivery_date"` + ApprovedDate *time.Time `json:"approved_date" db:"approved_date"` + FirstAvailableDeliveryDate *time.Time `json:"first_available_delivery_date" db:"first_available_delivery_date"` + ActualPickupDate *time.Time `json:"actual_pickup_date" db:"actual_pickup_date"` + RequiredDeliveryDate *time.Time `json:"required_delivery_date" db:"required_delivery_date"` + ScheduledDeliveryDate *time.Time `json:"scheduled_delivery_date" db:"scheduled_delivery_date"` + ActualDeliveryDate *time.Time `json:"actual_delivery_date" db:"actual_delivery_date"` + CustomerRemarks *string `json:"customer_remarks" db:"customer_remarks"` + CounselorRemarks *string `json:"counselor_remarks" db:"counselor_remarks"` + PickupAddress *Address `json:"pickup_address" belongs_to:"addresses" fk_id:"pickup_address_id"` + PickupAddressID *uuid.UUID `json:"pickup_address_id" db:"pickup_address_id"` + DestinationAddress *Address `json:"destination_address" belongs_to:"addresses" fk_id:"destination_address_id"` + DestinationAddressID *uuid.UUID `json:"destination_address_id" db:"destination_address_id"` + DestinationType *DestinationType `json:"destination_type" db:"destination_address_type"` + MTOAgents MTOAgents `json:"mto_agents" has_many:"mto_agents" fk_id:"mto_shipment_id"` + MTOServiceItems MTOServiceItems `json:"mto_service_items" has_many:"mto_service_items" fk_id:"mto_shipment_id"` + SecondaryPickupAddress *Address `json:"secondary_pickup_address" belongs_to:"addresses" fk_id:"secondary_pickup_address_id"` + SecondaryPickupAddressID *uuid.UUID `json:"secondary_pickup_address_id" db:"secondary_pickup_address_id"` + HasSecondaryPickupAddress *bool `json:"has_secondary_pickup_address" db:"has_secondary_pickup_address"` + SecondaryDeliveryAddress *Address `json:"secondary_delivery_address" belongs_to:"addresses" fk_id:"secondary_delivery_address_id"` + SecondaryDeliveryAddressID *uuid.UUID `json:"secondary_delivery_address_id" db:"secondary_delivery_address_id"` + HasSecondaryDeliveryAddress *bool `json:"has_secondary_delivery_address" db:"has_secondary_delivery_address"` + TertiaryPickupAddress *Address `json:"tertiary_pickup_address" belongs_to:"addresses" fk_id:"tertiary_pickup_address_id"` + TertiaryPickupAddressID *uuid.UUID `json:"tertiary_pickup_address_id" db:"tertiary_pickup_address_id"` + HasTertiaryPickupAddress *bool `json:"has_tertiary_pickup_address" db:"has_tertiary_pickup_address"` + TertiaryDeliveryAddress *Address `json:"tertiary_delivery_address" belongs_to:"addresses" fk_id:"tertiary_delivery_address_id"` + TertiaryDeliveryAddressID *uuid.UUID `json:"tertiary_delivery_address_id" db:"tertiary_delivery_address_id"` + HasTertiaryDeliveryAddress *bool `json:"has_tertiary_delivery_address" db:"has_tertiary_delivery_address"` + SITDaysAllowance *int `json:"sit_days_allowance" db:"sit_days_allowance"` + SITDurationUpdates SITDurationUpdates `json:"sit_duration_updates" has_many:"sit_extensions" fk_id:"mto_shipment_id"` + PrimeEstimatedWeight *unit.Pound `json:"prime_estimated_weight" db:"prime_estimated_weight"` + PrimeEstimatedWeightRecordedDate *time.Time `json:"prime_estimated_weight_recorded_date" db:"prime_estimated_weight_recorded_date"` + PrimeActualWeight *unit.Pound `json:"prime_actual_weight" db:"prime_actual_weight"` + BillableWeightCap *unit.Pound `json:"billable_weight_cap" db:"billable_weight_cap"` + BillableWeightJustification *string `json:"billable_weight_justification" db:"billable_weight_justification"` + NTSRecordedWeight *unit.Pound `json:"nts_recorded_weight" db:"nts_recorded_weight"` + ShipmentType MTOShipmentType `json:"shipment_type" db:"shipment_type"` + Status MTOShipmentStatus `json:"status" db:"status"` + Diversion bool `json:"diversion" db:"diversion"` + DiversionReason *string `json:"diversion_reason" db:"diversion_reason"` + DivertedFromShipmentID *uuid.UUID `json:"diverted_from_shipment_id" db:"diverted_from_shipment_id"` + ActualProGearWeight *unit.Pound `json:"actual_pro_gear_weight" db:"actual_pro_gear_weight"` + ActualSpouseProGearWeight *unit.Pound `json:"actual_spouse_pro_gear_weight" db:"actual_spouse_pro_gear_weight"` + RejectionReason *string `json:"rejection_reason" db:"rejection_reason"` + Distance *unit.Miles `json:"distance" db:"distance"` + Reweigh *Reweigh `json:"reweigh" has_one:"reweighs" fk_id:"shipment_id"` + UsesExternalVendor bool `json:"uses_external_vendor" db:"uses_external_vendor"` + StorageFacility *StorageFacility `json:"storage_facility" belongs_to:"storage_facilities" fk:"storage_facility_id"` + StorageFacilityID *uuid.UUID `json:"storage_facility_id" db:"storage_facility_id"` + ServiceOrderNumber *string `json:"service_order_number" db:"service_order_number"` + TACType *LOAType `json:"tac_type" db:"tac_type"` + SACType *LOAType `json:"sac_type" db:"sac_type"` + PPMShipment *PPMShipment `json:"ppm_shipment" has_one:"ppm_shipment" fk_id:"shipment_id"` + BoatShipment *BoatShipment `json:"boat_shipment" has_one:"boat_shipment" fk_id:"shipment_id"` + DeliveryAddressUpdate *ShipmentAddressUpdate `json:"delivery_address_update" has_one:"shipment_address_update" fk_id:"shipment_id"` + CreatedAt time.Time `json:"created_at" db:"created_at"` + UpdatedAt time.Time `json:"updated_at" db:"updated_at"` + DeletedAt *time.Time `json:"deleted_at" db:"deleted_at"` + ShipmentLocator *string `json:"shipment_locator" db:"shipment_locator"` + OriginSITAuthEndDate *time.Time `json:"origin_sit_auth_end_date" db:"origin_sit_auth_end_date"` + DestinationSITAuthEndDate *time.Time `json:"destination_sit_auth_end_date" db:"dest_sit_auth_end_date"` + MobileHome *MobileHome `json:"mobile_home" has_one:"mobile_home" fk_id:"shipment_id"` + MarketCode MarketCode `json:"market_code" db:"market_code"` } // TableName overrides the table name used by Pop. diff --git a/pkg/models/order.go b/pkg/models/order.go index 84d5c215349..1ba20fc038d 100644 --- a/pkg/models/order.go +++ b/pkg/models/order.go @@ -67,14 +67,14 @@ type Order struct { CreatedAt time.Time `json:"created_at" db:"created_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` ServiceMemberID uuid.UUID `json:"service_member_id" db:"service_member_id"` - ServiceMember ServiceMember `belongs_to:"service_members" fk_id:"service_member_id"` + ServiceMember ServiceMember `json:"service_member" belongs_to:"service_members" fk_id:"service_member_id"` IssueDate time.Time `json:"issue_date" db:"issue_date"` ReportByDate time.Time `json:"report_by_date" db:"report_by_date"` OrdersType internalmessages.OrdersType `json:"orders_type" db:"orders_type"` OrdersTypeDetail *internalmessages.OrdersTypeDetail `json:"orders_type_detail" db:"orders_type_detail"` HasDependents bool `json:"has_dependents" db:"has_dependents"` SpouseHasProGear bool `json:"spouse_has_pro_gear" db:"spouse_has_pro_gear"` - OriginDutyLocation *DutyLocation `belongs_to:"duty_locations" fk_id:"origin_duty_location_id"` + OriginDutyLocation *DutyLocation `json:"origin_duty_location" belongs_to:"duty_locations" fk_id:"origin_duty_location_id"` OriginDutyLocationID *uuid.UUID `json:"origin_duty_location_id" db:"origin_duty_location_id"` NewDutyLocationID uuid.UUID `json:"new_duty_location_id" db:"new_duty_location_id"` NewDutyLocation DutyLocation `belongs_to:"duty_locations" fk_id:"new_duty_location_id"` diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index cfbcebfec0d..b08329d3fef 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -2,6 +2,7 @@ package order import ( "database/sql" + "encoding/json" "fmt" "regexp" "strings" @@ -9,6 +10,8 @@ import ( "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" + "github.com/jinzhu/copier" + "github.com/lib/pq" "go.uber.org/zap" "github.com/transcom/mymove/pkg/appcontext" @@ -306,9 +309,31 @@ func (f orderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid return moves, count, nil } +type MoveWithCount struct { + models.Move + OrdersRaw json.RawMessage `json:"orders" db:"orders"` + Orders *models.Order `json:"-"` + MTOShipmentsRaw json.RawMessage `json:"mto_shipments" db:"mto_shipments"` + MTOShipments *models.MTOShipments `json:"-"` + CounselingOfficeRaw json.RawMessage `json:"counseling_transportation_office" db:"counseling_transportation_office"` + CounselingOffice *models.TransportationOffice `json:"-"` + TOOAssignedRaw json.RawMessage `json:"too_assigned" db:"too_assigned"` + TOOAssignedUser *models.OfficeUser `json:"-"` + TotalCount int64 `json:"total_count" db:"total_count"` +} + +type JSONB []byte + +func (j *JSONB) UnmarshalJSON(data []byte) error { + *j = data + return nil +} + func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext, officeUserID uuid.UUID, role roles.RoleType, params *services.ListOrderParams) ([]models.Move, int, error) { var moves []models.Move + var movesWithCount []MoveWithCount + // getting the office user's GBLOC var officeUserGbloc string if params.ViewAsGBLOC != nil { officeUserGbloc = *params.ViewAsGBLOC @@ -321,136 +346,81 @@ func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext } } - ppmCloseoutGblocs := officeUserGbloc == "NAVY" || officeUserGbloc == "TVCB" || officeUserGbloc == "USCG" + // calling the database function with all passed in parameters + err := appCtx.DB().RawQuery("SELECT * FROM get_destination_queue($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)", + officeUserGbloc, + params.CustomerName, + params.Edipi, + params.Emplid, + pq.Array(params.Status), + params.Locator, + params.RequestedMoveDate, + params.SubmittedAt, + params.Branch, + strings.Join(params.OriginDutyLocation, " "), + params.CounselingOffice, + params.TOOAssignedUser, + params.Page, + params.PerPage). + All(&movesWithCount) - branchQuery := branchFilter(params.Branch, false, ppmCloseoutGblocs) + if err != nil { + return []models.Move{}, 0, err + } - // If the user is associated with the USMC GBLOC we want to show them ALL the USMC moves, so let's override here. - // We also only want to do the gbloc filtering thing if we aren't a USMC user, which we cover with the else. - // var gblocQuery QueryOption - var gblocToFilterBy *string - if officeUserGbloc == "USMC" { - branchQuery = branchFilter(models.StringPointer(string(models.AffiliationMARINES)), false, ppmCloseoutGblocs) - gblocToFilterBy = params.OriginGBLOC + // each row is sent back with the total count, so we will take the value from the first one + var count int64 + if len(movesWithCount) > 0 { + count = movesWithCount[0].TotalCount } else { - gblocToFilterBy = &officeUserGbloc + count = 0 } - gblocQuery := gblocFilterForTOO(gblocToFilterBy) - - locatorQuery := locatorFilter(params.Locator) - dodIDQuery := dodIDFilter(params.Edipi) - emplidQuery := emplidFilter(params.Emplid) - customerNameQuery := customerNameFilter(params.CustomerName) - originDutyLocationQuery := originDutyLocationFilter(params.OriginDutyLocation) - destinationDutyLocationQuery := destinationDutyLocationFilter(params.DestinationDutyLocation) - moveStatusQuery := moveStatusFilter(params.Status) - submittedAtQuery := submittedAtFilter(params.SubmittedAt) - appearedInTOOAtQuery := appearedInTOOAtFilter(params.AppearedInTOOAt) - requestedMoveDateQuery := requestedMoveDateFilter(params.RequestedMoveDate) - closeoutInitiatedQuery := closeoutInitiatedFilter(params.CloseoutInitiated) - closeoutLocationQuery := closeoutLocationFilter(params.CloseoutLocation, ppmCloseoutGblocs) - ppmTypeQuery := ppmTypeFilter(params.PPMType) - ppmStatusQuery := ppmStatusFilter(params.PPMStatus) - scAssignedUserQuery := scAssignedUserFilter(params.SCAssignedUser) - tooAssignedUserQuery := tooAssignedUserFilter(params.TOOAssignedUser) - sortOrderQuery := sortOrder(params.Sort, params.Order, ppmCloseoutGblocs) - counselingQuery := counselingOfficeFilter(params.CounselingOffice) - - // Adding to an array so we can iterate over them and apply the filters after the query structure is set below - options := [20]QueryOption{branchQuery, locatorQuery, dodIDQuery, emplidQuery, customerNameQuery, originDutyLocationQuery, destinationDutyLocationQuery, moveStatusQuery, gblocQuery, submittedAtQuery, appearedInTOOAtQuery, requestedMoveDateQuery, ppmTypeQuery, closeoutInitiatedQuery, closeoutLocationQuery, ppmStatusQuery, sortOrderQuery, scAssignedUserQuery, tooAssignedUserQuery, counselingQuery} - - // we want to set the query up to where it only shows moves that have orders.destination_gbloc that are in the office user's GBLOC (some exclusions apply) - query := appCtx.DB().Q().Scope(utilities.ExcludeDeletedScope(models.MTOShipment{})).EagerPreload( - "Orders.ServiceMember", - "Orders.NewDutyLocation.Address", - "Orders.OriginDutyLocation.Address", - "Orders.Entitlement", - "MTOShipments.DeliveryAddressUpdate", - "MTOServiceItems.ReService.Code", - "ShipmentGBLOC", - "MTOShipments.PPMShipment", - "CloseoutOffice", - "LockedByOfficeUser", - "CounselingOffice", - "SCAssignedUser", - "TOOAssignedUser", - ).InnerJoin("orders", "orders.id = moves.orders_id"). - InnerJoin("service_members", "orders.service_member_id = service_members.id"). - InnerJoin("mto_shipments", "moves.id = mto_shipments.move_id"). - InnerJoin("mto_service_items", "mto_shipments.id = mto_service_items.mto_shipment_id"). - InnerJoin("re_services", "mto_service_items.re_service_id = re_services.id"). - InnerJoin("duty_locations as origin_dl", "orders.origin_duty_location_id = origin_dl.id"). - LeftJoin("transportation_offices as origin_to", "origin_dl.transportation_office_id = origin_to.id"). - LeftJoin("move_to_gbloc", "move_to_gbloc.move_id = moves.id"). - LeftJoin("duty_locations as dest_dl", "dest_dl.id = orders.new_duty_location_id"). - LeftJoin("office_users", "office_users.id = moves.locked_by"). - LeftJoin("transportation_offices", "moves.counseling_transportation_office_id = transportation_offices.id"). - LeftJoin("office_users as assigned_user", "moves.too_assigned_id = assigned_user.id"). - LeftJoin("ppm_shipments", "ppm_shipments.shipment_id = mto_shipments.id"). - LeftJoin("shipment_address_updates", "shipment_address_updates.shipment_id = mto_shipments.id"). - Where("moves.status = 'APPROVALS REQUESTED' "+ - "AND mto_service_items.status = 'SUBMITTED' "+ - "AND re_services.code IN ('DDFSIT', 'DDASIT', 'DDDSIT', 'DDSHUT', 'DDSFSC') "+ - "OR shipment_address_updates.status = 'REQUESTED'"). - Where("orders.destination_gbloc = ?", officeUserGbloc). - Where("moves.show = ?", models.BoolPointer(true)) - - for _, option := range options { - if option != nil { - option(query) + // we have to manually loop through each move and populate the nested objects that the queue uses/needs + for i := range movesWithCount { + // populating Move.Orders struct + var order models.Order + if err := json.Unmarshal(movesWithCount[i].OrdersRaw, &order); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling orders JSON: %w", err) } - } - - // Pass zeros into paginate in this case. Which will give us 1 page and 20 per page respectively - if params.Page == nil { - params.Page = models.Int64Pointer(0) - } - if params.PerPage == nil { - params.PerPage = models.Int64Pointer(0) - } + movesWithCount[i].OrdersRaw = nil + movesWithCount[i].Orders = &order - var groupByColumms []string - groupByColumms = append(groupByColumms, "service_members.id", "orders.id", "origin_dl.id") - - if params.Sort != nil && *params.Sort == "originDutyLocation" { - groupByColumms = append(groupByColumms, "origin_dl.name") - } - if params.Sort != nil && *params.Sort == "destinationDutyLocation" { - groupByColumms = append(groupByColumms, "dest_dl.name") - } - if params.Sort != nil && *params.Sort == "originGBLOC" { - groupByColumms = append(groupByColumms, "origin_to.id") - } - if params.Sort != nil && *params.Sort == "counselingOffice" { - groupByColumms = append(groupByColumms, "transportation_offices.id") - } - if params.Sort != nil && *params.Sort == "assignedTo" { - groupByColumms = append(groupByColumms, "assigned_user.last_name", "assigned_user.first_name") - } - - err := query.GroupBy("moves.id", groupByColumms...).Paginate(int(*params.Page), int(*params.PerPage)).All(&moves) - if err != nil { - return []models.Move{}, 0, err - } + // populating Move.MTOShipments array + var shipments models.MTOShipments + if err := json.Unmarshal(movesWithCount[i].MTOShipmentsRaw, &shipments); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling shipments JSON: %w", err) + } + movesWithCount[i].MTOShipmentsRaw = nil + movesWithCount[i].MTOShipments = &shipments - count := query.Paginator.TotalEntriesSize + // populating Moves.CounselingOffice struct + var counselingTransportationOffice models.TransportationOffice + if err := json.Unmarshal(movesWithCount[i].CounselingOfficeRaw, &counselingTransportationOffice); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling counseling_transportation_office JSON: %w", err) + } + movesWithCount[i].CounselingOfficeRaw = nil + movesWithCount[i].CounselingOffice = &counselingTransportationOffice - for i := range moves { - if moves[i].Orders.OriginDutyLocation != nil { - loadErr := appCtx.DB().Load(moves[i].Orders.OriginDutyLocation, "TransportationOffice") - if loadErr != nil { - return []models.Move{}, 0, err - } + // populating Moves.TOOAssigned struct + var tooAssigned models.OfficeUser + if err := json.Unmarshal(movesWithCount[i].TOOAssignedRaw, &tooAssigned); err != nil { + return nil, 0, fmt.Errorf("error unmarshaling too_assigned JSON: %w", err) } + movesWithCount[i].TOOAssignedRaw = nil + movesWithCount[i].TOOAssignedUser = &tooAssigned + } - err := appCtx.DB().Load(&moves[i].Orders.ServiceMember, "BackupContacts") - if err != nil { - return []models.Move{}, 0, err + // the handler consumes a Move object, so we have to copy our custom struct into the Move struct + for _, moveWithCount := range movesWithCount { + var move models.Move + if err := copier.Copy(&move, &moveWithCount); err != nil { + return nil, 0, fmt.Errorf("error copying movesWithCount into Moves: %w", err) } + moves = append(moves, move) } - return moves, count, nil + return moves, int(count), nil } func (f orderFetcher) ListAllOrderLocations(appCtx appcontext.AppContext, officeUserID uuid.UUID, params *services.ListOrderParams) ([]models.Move, error) { diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index 63f6083a887..b2bcc94b3b8 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -3819,6 +3819,8 @@ paths: items: type: string enum: + - SUBMITTED + - SERVICE COUNSELING COMPLETED - APPROVALS REQUESTED - in: query name: orderType diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index 6df16f2884f..073a948672d 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -3990,6 +3990,8 @@ paths: items: type: string enum: + - SUBMITTED + - SERVICE COUNSELING COMPLETED - APPROVALS REQUESTED - in: query name: orderType From 74b5d0997531fd67dd57fe6ca053b21d2b64097f Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Mon, 27 Jan 2025 15:00:26 +0000 Subject: [PATCH 03/21] refactoring using USING, need to add USMC logic and refine --- ...73216_add_destination_queue_db_func.up.sql | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql index f6c40773200..fad30b87d29 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql @@ -112,8 +112,7 @@ BEGIN WHERE moves.show = TRUE '; - -- adding conditionals for destination queue - -- we only want to see moves that have destination requests (shipment address updates, destination service items in SUBMITTED status) + -- add destination queue-specific filters (pending dest address requests, dest SIT & shuttle service items) sql_query := sql_query || ' AND ( shipment_address_updates.status = ''REQUESTED'' @@ -124,60 +123,59 @@ BEGIN ) '; - -- this should always be passed in from the service object, but will nil check it anyway IF user_gbloc IS NOT NULL THEN - sql_query := sql_query || ' AND move_to_gbloc.gbloc = ''%' || user_gbloc || '%'' '; + sql_query := sql_query || ' AND move_to_gbloc.gbloc = $1 '; END IF; - IF customer_name IS NOT NULL AND customer_name <> '' THEN + IF customer_name IS NOT NULL THEN sql_query := sql_query || ' AND ( - service_members.first_name || '' '' || service_members.last_name ILIKE ''%' || customer_name || '%'' - OR service_members.last_name || '' '' || service_members.first_name ILIKE ''%' || customer_name || '%'' - ) '; + service_members.first_name || '' '' || service_members.last_name ILIKE ''%'' || $2 || ''%'' + OR service_members.last_name || '' '' || service_members.first_name ILIKE ''%'' || $2 || ''%'' + )'; END IF; IF edipi IS NOT NULL THEN - sql_query := sql_query || ' AND service_members.edipi ILIKE ''%' || edipi || '%'' '; + sql_query := sql_query || ' AND service_members.edipi ILIKE ''%'' || $3 || ''%'' '; END IF; IF emplid IS NOT NULL THEN - sql_query := sql_query || ' AND service_members.emplid ILIKE ''%' || emplid || '%'' '; + sql_query := sql_query || ' AND service_members.emplid ILIKE ''%'' || $4 || ''%'' '; END IF; IF m_status IS NOT NULL THEN - sql_query := sql_query || ' AND moves.status IN (SELECT unnest($1)) '; + sql_query := sql_query || ' AND moves.status = ANY($5) '; END IF; IF move_code IS NOT NULL THEN - sql_query := sql_query || ' AND moves.locator ILIKE ''%' || UPPER(move_code) || '%'' '; + sql_query := sql_query || ' AND moves.locator ILIKE ''%'' || $6 || ''%'' '; END IF; IF requested_move_date IS NOT NULL THEN sql_query := sql_query || ' AND ( - mto_shipments.requested_pickup_date::DATE = ' || quote_literal(requested_move_date) || '::DATE - OR ppm_shipments.expected_departure_date::DATE = ' || quote_literal(requested_move_date) || '::DATE - OR (mto_shipments.shipment_type = ''HHG_OUTOF_NTS'' AND mto_shipments.requested_delivery_date::DATE = ' || quote_literal(requested_move_date) || '::DATE) + mto_shipments.requested_pickup_date::DATE = $7::DATE + OR ppm_shipments.expected_departure_date::DATE = $7::DATE + OR (mto_shipments.shipment_type = ''HHG_OUTOF_NTS'' AND mto_shipments.requested_delivery_date::DATE = $7::DATE) )'; END IF; IF date_submitted IS NOT NULL THEN - sql_query := sql_query || ' AND moves.submitted_at = ' || quote_literal(date_submitted) || ' '; + sql_query := sql_query || ' AND moves.submitted_at::DATE = $8::DATE '; END IF; IF branch IS NOT NULL THEN - sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%' || branch || '%'' '; + sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%'' || $9 || ''%'' '; END IF; - IF origin_duty_location IS NOT NULL AND origin_duty_location <> '' THEN - sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%' || origin_duty_location || '%'' '; + IF origin_duty_location IS NOT NULL THEN + sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%'' || $10 || ''%'' '; END IF; IF counseling_office IS NOT NULL THEN - sql_query := sql_query || ' AND counseling_offices.name ILIKE ''%' || counseling_office || '%'' '; + sql_query := sql_query || ' AND counseling_offices.name ILIKE ''%'' || $11 || ''%'' '; END IF; IF too_assigned_user IS NOT NULL THEN - sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%' || quote_literal(too_assigned_user) || '%'' '; + sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%'' || $12 || ''%'' '; END IF; sql_query := sql_query || ' @@ -202,11 +200,11 @@ BEGIN too_user.first_name, too_user.last_name'; sql_query := sql_query || ' ORDER BY moves.id ASC '; - sql_query := sql_query || ' LIMIT ' || per_page || ' OFFSET ' || offset_value || ' '; - - RAISE NOTICE 'Query: %', sql_query; + sql_query := sql_query || ' LIMIT $13 OFFSET $14 '; - RETURN QUERY EXECUTE sql_query USING m_status; + RETURN QUERY EXECUTE sql_query + USING user_gbloc, customer_name, edipi, emplid, m_status, move_code, requested_move_date, date_submitted, + branch, origin_duty_location, counseling_office, too_assigned_user, per_page, offset_value; END; $$ LANGUAGE plpgsql; From 5fb02b3014ae6e032d089bd15ee75fca60ec4950 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 28 Jan 2025 15:41:55 +0000 Subject: [PATCH 04/21] added move to dest gbloc view --- migrations/app/migrations_manifest.txt | 2 +- ...ation_queue_db_func_and_gbloc_view.up.sql} | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) rename migrations/app/schema/{20250123173216_add_destination_queue_db_func.up.sql => 20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql} (78%) diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index fefc26f6685..c8c62bb5807 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1075,4 +1075,4 @@ 20250113201232_update_estimated_pricing_procs_add_is_peak_func.up.sql 20250116200912_disable_homesafe_stg_cert.up.sql 20250120144247_update_pricing_proc_to_use_110_percent_weight.up.sql -20250123173216_add_destination_queue_db_func.up.sql +20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql similarity index 78% rename from migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql rename to migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql index fad30b87d29..f6d740023d1 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -1,3 +1,43 @@ +CREATE OR REPLACE VIEW move_to_dest_gbloc +AS +SELECT distinct move_id, gbloc FROM ( + SELECT sh.move_id, s.affiliation, + COALESCE(pctg.gbloc, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + FROM mto_shipments sh + JOIN moves m ON sh.move_id = m.id + JOIN orders o on m.orders_id = o.id + JOIN service_members s on o.service_member_id = s.id + LEFT JOIN ( SELECT a.id AS address_id, + pctg_1.gbloc, pctg_1.postal_code + FROM addresses a + JOIN postal_code_to_gblocs pctg_1 ON a.postal_code::text = pctg_1.postal_code::text) pctg ON pctg.address_id = sh.destination_address_id + LEFT JOIN ( SELECT ppm.shipment_id, + pctg_1.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.destination_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg_1 ON ppm_address.postal_code::text = pctg_1.postal_code::text) pctg_ppm ON pctg_ppm.shipment_id = sh.id + LEFT JOIN ( SELECT a.id AS address_id, + cast(jr.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions jr ON ga.jppso_regions_id = jr.id + ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.destination_address_id + and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'NAVY' THEN 'NAVY_AND_MARINES' + when s.affiliation = 'MARINES' THEN 'NAVY_AND_MARINES' + else s.affiliation + end = pctg_oconus_bos.department_indicator + LEFT JOIN ( SELECT a.id AS address_id, + cast(pctg_1.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions pctg_1 ON ga.jppso_regions_id = pctg_1.id + ) pctg_oconus ON pctg_oconus.address_id = sh.destination_address_id and pctg_oconus.department_indicator is null + WHERE sh.deleted_at IS NULL) as m; + -- database function that returns a list of moves that have destination requests -- this includes shipment address update requests & destination service items CREATE OR REPLACE FUNCTION get_destination_queue( From 4a2ab0d530f79e3de29a1556753cb70dc52b474e Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Wed, 29 Jan 2025 16:05:52 +0000 Subject: [PATCH 05/21] updating move_to_gbloc to move_to_dest_gbloc --- ...23173216_add_destination_queue_db_func_and_gbloc_view.up.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql index f6d740023d1..bda0e93ab39 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -148,7 +148,7 @@ BEGIN LEFT JOIN transportation_offices AS counseling_offices ON moves.counseling_transportation_office_id = counseling_offices.id LEFT JOIN shipment_address_updates ON shipment_address_updates.shipment_id = mto_shipments.id - LEFT JOIN move_to_gbloc ON move_to_gbloc.move_id = moves.id + LEFT JOIN move_to_dest_gbloc ON move_to_dest_gbloc.move_id = moves.id WHERE moves.show = TRUE '; From c997ab5e0cb5504e003b32cf6cabebb335d1469b Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Fri, 31 Jan 2025 14:15:23 +0000 Subject: [PATCH 06/21] adding things, awaiting db funcs from beth for USMC logic --- ...nation_queue_db_func_and_gbloc_view.up.sql | 261 ++++++++++++++++-- .../ServicesCounselingQueue.jsx | 2 +- 2 files changed, 237 insertions(+), 26 deletions(-) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql index bda0e93ab39..bd09ad533c4 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -1,3 +1,210 @@ +--insert USMC gbloc +insert into jppso_regions values ('85b324ae-1a0d-4f7d-971f-ea509dcc73d7', 'USMC','USMC',now(),now()); + +--insert USMC AORs +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('a8eb35e2-275e-490b-9945-1971b954b958'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e418be11-2b6f-4714-b026-e293528c50bd'::uuid,'MARINES',NULL,true,now(),now()), + ('ada1b48d-d2e0-481a-8a2e-a265a824647d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b41c5636-96dd-4f0d-a18e-eebb17f97ea5'::uuid,'MARINES',NULL,true,now(),now()), + ('588af482-7cd7-42ea-8e05-49dce645ecbe'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'02f32a6a-0338-4545-8437-059862892d2c'::uuid,'MARINES',NULL,true,now(),now()), + ('1ff3bed7-bbf3-432d-9da3-d76264d72913'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0f128476-d52a-418c-8ba0-c8bfd1c32629'::uuid,'MARINES',NULL,true,now(),now()), + ('0853a854-98b2-4363-a2b1-db14c44dde2f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'081f84c3-17ec-4ff6-97ce-d5c44a8e4a28'::uuid,'MARINES',NULL,true,now(),now()), + ('21c1ba40-2533-4196-9eb5-6ffddff3a794'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ce7cdd91-e323-43a6-a604-daaa6bf8be06'::uuid,'MARINES',NULL,true,now(),now()), + ('19ca4073-8736-453e-bb0d-9b13e3b557b0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'655050d4-711a-43b7-b06d-828ec990c35e'::uuid,'MARINES',NULL,true,now(),now()), + ('a9c2131e-09c3-480d-ba3e-0c144de18aa5'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'455a34af-30a8-4a98-a62b-6f40fd7f047b'::uuid,'MARINES',NULL,true,now(),now()), + ('649e72f8-cac8-483f-a9ed-c9659e37545b'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1bf1daee-51bb-4c28-aac8-a126ef596486'::uuid,'MARINES',NULL,true,now(),now()), + ('7173f871-f948-4eed-86ae-5e977b16c426'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15b1d852-0dde-4e1b-b3c6-e08bbc714db3'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('4f626e2a-cad0-4b4d-baa8-3101275bac23'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d63de5bb-379b-4f3b-b4c1-554b9746d311'::uuid,'MARINES',NULL,true,now(),now()), + ('de59c604-9119-48fc-bf3f-883de17b7ee6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'95d142f8-b50a-4108-b5e2-fbd3b7022d3b'::uuid,'MARINES',NULL,true,now(),now()), + ('1cec884c-9e34-42fe-8887-1e8b8fa1cd2e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'922bb7da-d0e9-431c-a493-95a861dca929'::uuid,'MARINES',NULL,true,now(),now()), + ('0f24b453-e3bc-47ec-86b5-8d8937f65504'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'79aef0ca-9065-4c0e-a134-2889b250cc38'::uuid,'MARINES',NULL,true,now(),now()), + ('2d55560a-7d0a-474f-a0f9-b31c5be8d80e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1f181025-e410-41ac-935b-4b5147353f84'::uuid,'MARINES',NULL,true,now(),now()), + ('abcc37f6-9209-4639-8fa1-c8d5f6e4e77d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d9ede620-c3f1-4f8d-b60b-eb93664382f7'::uuid,'MARINES',NULL,true,now(),now()), + ('3ac990d2-5df4-4889-a943-2710f818e75a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'bd27700b-3094-46cc-807b-f18472cbfaf0'::uuid,'MARINES',NULL,true,now(),now()), + ('f3084090-680f-4656-947a-eb2e773e4076'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'2f4a1689-ee65-45fa-9d0c-debd9344f8b9'::uuid,'MARINES',NULL,true,now(),now()), + ('a35ac50b-09a1-46ef-969e-17569717ee10'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'20c52934-2588-4d8f-b3ed-c046d771f4e9'::uuid,'MARINES',NULL,true,now(),now()), + ('107c1479-e6d9-44cb-8342-ac934055074d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15fe364b-add5-4ade-bdd9-38fe442616fb'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('843db089-67cb-463d-a255-1d198f4f7aaa'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e5a1248e-3870-4a4c-9c9d-2056234eb64a'::uuid,'MARINES',NULL,true,now(),now()), + ('ac820ac9-d380-4c11-9103-172795658e1f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'efc92db1-4b06-49ab-a295-a98f3f6c9c04'::uuid,'MARINES',NULL,true,now(),now()), + ('dca7ccd2-e438-4f82-8b76-9b61fbf2a593'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'13474ce5-8839-4af7-b975-c3f70ccdab7b'::uuid,'MARINES',NULL,true,now(),now()), + ('def1095b-2a5c-4f7c-8889-9fde15a7ec06'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d3b05c5e-6faa-4fa9-b725-0904f8a4f3d7'::uuid,'MARINES',NULL,true,now(),now()), + ('d5fbc738-ee31-4c51-8fd4-bbb8db941dc1'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e5f849fe-5672-4d0d-881c-078e56eea33d'::uuid,'MARINES',NULL,true,now(),now()), + ('ac8c75fe-f637-429d-80fa-913321a65372'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'fca7c60e-fbd9-4885-afdb-ae41c521b560'::uuid,'MARINES',NULL,true,now(),now()), + ('c33eb1f8-b0fc-4670-af5e-5bd423eca6e7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0d52a0f0-f39c-4d34-9387-2df45a5810d4'::uuid,'MARINES',NULL,true,now(),now()), + ('188ea995-b8b7-4ce0-97a9-f553f3b72c2f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'af008e75-81d5-4211-8204-4964c78e70d9'::uuid,'MARINES',NULL,true,now(),now()), + ('4f13c1a6-059b-4aa2-9250-4316e60da2a7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'dd689e55-af29-4c76-b7e0-c2429ea4833c'::uuid,'MARINES',NULL,true,now(),now()), + ('67e1ff6f-b79b-45cf-b250-3d4ec89bebae'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'60e08330-6869-4586-8198-35f7a4ae9ea7'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('3a7c679c-0439-4030-8f7e-f6d8e92720d7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f7478e79-dbfe-46c8-b337-1e7c46df79dc'::uuid,'MARINES',NULL,true,now(),now()), + ('db91f133-a301-4c87-af9f-6c10584063e6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'486d7dd4-f51f-4b13-88fc-830b5b15f0a8'::uuid,'MARINES',NULL,true,now(),now()), + ('6b83cc22-36a9-470e-9f43-e65ade5e8a66'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f66edf62-ba5e-47f8-8264-b6dc9e7dd9ba'::uuid,'MARINES',NULL,true,now(),now()), + ('3df30221-acd3-4428-890c-3a5ef5296cb1'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0052c55a-d9d7-46b0-9328-58d3911f61b4'::uuid,'MARINES',NULL,true,now(),now()), + ('bae4c9c6-94d8-4ad0-bfc0-7642f5353199'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'16a51fd1-04ed-432a-a8d7-9f17c1de095d'::uuid,'MARINES',NULL,true,now(),now()), + ('1cd873ff-d170-4f48-8f5b-5c5146052d68'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'64b4756f-437d-4aa5-a95e-c396f0cafcbb'::uuid,'MARINES',NULL,true,now(),now()), + ('eb4d870b-8d66-4135-b294-8992e56ad76f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f2de1da5-a737-4493-b3f7-7700944a5b62'::uuid,'MARINES',NULL,true,now(),now()), + ('e8c0709c-1f08-4d3e-b848-72ab5b524677'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'7a9c2adb-0562-42c1-a5f1-81710dd19590'::uuid,'MARINES',NULL,true,now(),now()), + ('3c53df36-ee6b-4bc0-a5ca-cedc1dc3c32e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e713eed6-35a6-456d-bfb2-0e0646078ab8'::uuid,'MARINES',NULL,true,now(),now()), + ('7cbc7e6c-4da7-47a1-ac93-171b89dba1e0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a4594957-0ec6-4edc-85c2-68871f4f6359'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('d22cb1d2-79b4-45c9-bb6f-8acef54a67b0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'acd4d2f9-9a49-4a73-be14-3515f19ba0d1'::uuid,'MARINES',NULL,true,now(),now()), + ('5b5e7a5a-d027-44f2-9b4f-f25c1a91bc00'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c8300ab6-519c-4bef-9b81-25e7334773ca'::uuid,'MARINES',NULL,true,now(),now()), + ('21307477-912d-40ca-a399-6dfebcc322ea'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'67eca2ce-9d88-44ca-bb17-615f3199415c'::uuid,'MARINES',NULL,true,now(),now()), + ('82282efb-7fef-4a6d-a260-a18d2f21fa8d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'149c3a94-abb1-4af0-aabf-3af019d5e243'::uuid,'MARINES',NULL,true,now(),now()), + ('3bdad313-d414-4842-8e6e-3675e20d78eb'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'87c09b47-058e-47ea-9684-37a8ac1f7120'::uuid,'MARINES',NULL,true,now(),now()), + ('db80b591-045d-4907-9b77-6694fe34e3ed'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0ba81e85-f175-435a-a7c2-a22d0c44cc7b'::uuid,'MARINES',NULL,true,now(),now()), + ('05970a8a-28aa-454f-a28e-31327a2415dd'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'946256dc-1572-4201-b5ff-464da876f5ff'::uuid,'MARINES',NULL,true,now(),now()), + ('c1b3e0be-0463-4dfc-ab22-016037b41a05'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5d381518-6beb-422e-8c57-4682b87ff1fe'::uuid,'MARINES',NULL,true,now(),now()), + ('1a92f4b0-4060-4f1b-9b45-b3fc47c5f08d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b07fb701-2c9b-4847-a459-76b1f47aa872'::uuid,'MARINES',NULL,true,now(),now()), + ('73794c53-a915-41af-b93d-5ada2e174409'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b6c51584-f3e8-4c9e-9bdf-f7cac0433319'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('c03994c2-9e2a-4888-a5c2-c81ee05eba31'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'6097d01d-78ef-40d5-8699-7f8a8e48f4e7'::uuid,'MARINES',NULL,true,now(),now()), + ('ae6a55fd-2171-425a-9716-56d3fb9452e3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e48a3602-7fdd-4527-a8a7-f244fb331228'::uuid,'MARINES',NULL,true,now(),now()), + ('f052acf4-7d4a-4061-a2f4-ba19ff17ec4d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'df47ef29-e902-4bd3-a32d-88d6187399b3'::uuid,'MARINES',NULL,true,now(),now()), + ('10b47428-bef7-4cfe-8564-2ccb654d514a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0f4eddf9-b727-4725-848e-3d9329553823'::uuid,'MARINES',NULL,true,now(),now()), + ('4a547501-6aae-4886-be5c-e5a0fad05441'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d16ebe80-2195-48cf-ba61-b5efb8212754'::uuid,'MARINES',NULL,true,now(),now()), + ('d99cbe3a-84a0-4a2c-8e05-41ce066570ea'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'093268d0-597b-40bd-882a-8f385480bc68'::uuid,'MARINES',NULL,true,now(),now()), + ('ad09f13c-9dd9-468b-ab92-ad3e2d77c905'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'edb8b022-9534-44e7-87ea-e93f5451f057'::uuid,'MARINES',NULL,true,now(),now()), + ('362482c6-7770-49f4-86c9-89e2990e5345'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4c62bb35-4d2a-4995-9c4f-8c665f2f6d3e'::uuid,'MARINES',NULL,true,now(),now()), + ('45994e2f-1aa4-4aa1-8631-a347a4463bc2'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'58ccfcc5-ded6-4f91-8cb7-8687bc56c4c6'::uuid,'MARINES',NULL,true,now(),now()), + ('b4fd2bf2-05b2-4429-afcb-ebbae512fd2b'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'dbc839c6-7b56-45b0-ab36-a0e77b0d538c'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('5aa5f596-a9bb-4f37-af0b-6e0cfbfbc711'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c77e434a-1bf9-44c6-92aa-d377d72d1d44'::uuid,'MARINES',NULL,true,now(),now()), + ('c7bc79d4-525e-496d-93bd-2ea76b32baf4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'89533190-e613-4c36-99df-7ee3871bb071'::uuid,'MARINES',NULL,true,now(),now()), + ('5bc99ccb-7010-4d2f-99a0-9277eda982ba'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c86cb50a-99f6-41ed-8e9d-f096bd5cadca'::uuid,'MARINES',NULL,true,now(),now()), + ('dc97dd55-213b-4212-8c1a-aaee7b92fc55'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b65bd7c4-6251-4682-aa07-77f761c363af'::uuid,'MARINES',NULL,true,now(),now()), + ('3a4daddc-a377-440f-bb5f-d33024374e3e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'88df8618-798a-4a12-9b14-a7267a6cfd7f'::uuid,'MARINES',NULL,true,now(),now()), + ('e729c30a-0bec-424a-919a-45cbe31998e9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15894c4f-eb1a-4b6b-8b3f-e3abc4eeee8d'::uuid,'MARINES',NULL,true,now(),now()), + ('74b6df4f-08ea-48fb-9628-15c3f47f3a27'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'83fd3eb7-6269-46e2-84e1-f6180f40b9e8'::uuid,'MARINES',NULL,true,now(),now()), + ('643112a7-71a9-41d1-97f6-92aee969478a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b0f95e07-e3d1-4403-a402-50be9a542cf9'::uuid,'MARINES',NULL,true,now(),now()), + ('73b35029-077b-4d30-8f5a-34c3785f6e96'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'cef18ff2-8f48-47c0-8062-a40f9dec641c'::uuid,'MARINES',NULL,true,now(),now()), + ('9d8862ec-4358-497a-8154-65a83c676261'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'15eefe71-55ae-40b0-8bb5-f1952fcf45c8'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('8d5591d4-fcc4-44a9-babd-b575672ad6a9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d3c5d0a7-0477-44f6-8279-f6b9fa7b3436'::uuid,'MARINES',NULL,true,now(),now()), + ('c1057fc7-1c8b-44e2-a175-131ff0d7429f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'8b89e7d7-cb36-40bd-ba14-699f1e4b1806'::uuid,'MARINES',NULL,true,now(),now()), + ('ae7949e2-9504-4874-92be-98460e8126da'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5b833661-8fda-4f2a-9f2b-e1f4c21749a4'::uuid,'MARINES',NULL,true,now(),now()), + ('acf2cacd-0d4f-4de1-afdc-2eb1e72eeb80'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'38bed277-7990-460d-ad27-a69559638f42'::uuid,'MARINES',NULL,true,now(),now()), + ('c66c3d59-def9-4e08-8bee-5b2bacfc5cfd'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'67081e66-7e84-4bac-9c31-aa3e45bbba23'::uuid,'MARINES',NULL,true,now(),now()), + ('1f8cd63a-8dfe-4357-9ac5-2bef71f9d564'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'99e3f894-595f-403a-83f5-f7e035dd1f20'::uuid,'MARINES',NULL,true,now(),now()), + ('3e8030da-8316-4330-abea-35452e39fa61'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1c0a5988-492f-4bc2-8409-9a143a494248'::uuid,'MARINES',NULL,true,now(),now()), + ('ce3c740a-b0a2-4a55-9abe-c2426fb8d821'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'63e10b54-5348-4362-932e-6613a8db4d42'::uuid,'MARINES',NULL,true,now(),now()), + ('9e913f22-287f-4e42-9544-46d9c6741db7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'437e9930-0625-4448-938d-ba93a0a98ab5'::uuid,'MARINES',NULL,true,now(),now()), + ('d0ae21fe-07c0-40ee-9aa3-877d6d6a6bb9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'87d3cb47-1026-4f42-bff6-899ff0fa7660'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('6f8d7c90-7682-41b7-b5cc-9d4aeb2e22ef'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0115586e-be8c-4808-b65a-d417fad19238'::uuid,'MARINES',NULL,true,now(),now()), + ('cf7f39c0-8f6b-4598-85db-f465241e66f4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'6638a77d-4b91-48f6-8241-c87fbdddacd1'::uuid,'MARINES',NULL,true,now(),now()), + ('296a8951-19b1-4868-9937-aef61bb73106'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'97c16bc3-e174-410b-9a09-a0db31420dbc'::uuid,'MARINES',NULL,true,now(),now()), + ('cdcec10e-5300-443f-9aae-7d8ce07142b0'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'3c6c5e35-1281-45fc-83ee-e6d656e155b6'::uuid,'MARINES',NULL,true,now(),now()), + ('e638701f-f8fc-48c0-b2e0-db134b9ece1f'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'6af248be-e5a8-49e9-a9e2-516748279ab5'::uuid,'MARINES',NULL,true,now(),now()), + ('ed4f4905-b1cf-4e57-beac-bc0a2d167c71'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'3580abe3-84da-4b46-af7b-d4379e6cff46'::uuid,'MARINES',NULL,true,now(),now()), + ('2a8b16c9-99f8-43ca-a759-c4884f8f7b24'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f3bb397e-04e6-4b37-9bf3-b3ebab79a9b6'::uuid,'MARINES',NULL,true,now(),now()), + ('70530105-a4ab-4af3-ba02-9e4cf81237fa'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f9bfe297-4ee0-4f76-a4bd-64b3a514af5d'::uuid,'MARINES',NULL,true,now(),now()), + ('61e17c04-ed7b-4da9-816a-1b6343086d94'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'70f11a71-667b-422d-ae37-8f25539f7782'::uuid,'MARINES',NULL,true,now(),now()), + ('19d5158f-96a6-48ef-8dd9-b831c582c9c4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'baf66a9a-3c8a-49e7-83ea-841b9960e184'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('91043072-657f-4b2a-b5d1-42d8f6a7ba38'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e96d46b1-3ab7-4b29-b798-ec3b728dd6a1'::uuid,'MARINES',NULL,true,now(),now()), + ('a3dc835e-3989-4476-b560-006745a884bc'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e4171b5b-d26c-43b3-b41c-68b43bcbb079'::uuid,'MARINES',NULL,true,now(),now()), + ('0cf1dc14-0c9a-4262-9cab-db73c64f6e36'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a0651bec-1258-4e36-9c76-155247e42c0a'::uuid,'MARINES',NULL,true,now(),now()), + ('e03b53cb-386f-4e1e-ac93-cd1a9260c6b4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'737a8e63-af19-4902-a4b5-8f80e2268e4b'::uuid,'MARINES',NULL,true,now(),now()), + ('8b3f1142-f6d4-4c2d-9e75-9ab3568742f7'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'870df26e-2c50-4512-aa2e-61094cfbc3e1'::uuid,'MARINES',NULL,true,now(),now()), + ('5f5383b8-f29e-4b9f-8798-99575440c888'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'09dc6547-d346-40c3-93fb-fb7be1fa1b3e'::uuid,'MARINES',NULL,true,now(),now()), + ('1f7a198c-5f62-4f8c-bf91-19d7cdef9bae'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'43d7d081-bb32-4544-84f1-419fe0cb76e1'::uuid,'MARINES',NULL,true,now(),now()), + ('56c17bab-a124-4710-a047-0d67d30a9610'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d7e57942-9c83-4138-baa0-70e8b5f08598'::uuid,'MARINES',NULL,true,now(),now()), + ('aad1440d-acaf-4ba8-9564-da97ab9ba651'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c2f06691-5989-41a3-a848-19c9f0fec5df'::uuid,'MARINES',NULL,true,now(),now()), + ('6cc24224-2298-4023-888f-5e624e585171'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5263a9ed-ff4d-42cc-91d5-dbdefeef54d1'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('88cd8184-7e3a-48cf-bb72-a9e1c3666cc4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'54ab3a49-6d78-4922-bac1-94a722b9859a'::uuid,'MARINES',NULL,true,now(),now()), + ('11fdac1c-7ae9-49ea-bee4-90d4582f7c6d'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'3b6fe2e9-9116-4a70-8eef-96205205b0e3'::uuid,'MARINES',NULL,true,now(),now()), + ('83c88ffb-5182-42b3-93f4-635556d8caaf'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ba0017c8-5d48-4efe-8802-361d2f2bc16d'::uuid,'MARINES',NULL,true,now(),now()), + ('802f7a5f-8ce3-4c40-975a-83cf0ec502fc'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'af65234a-8577-4f6d-a346-7d486e963287'::uuid,'MARINES',NULL,true,now(),now()), + ('5197eed4-f6ae-4f70-b640-b67714b73f87'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'25f62695-ba9b-40c3-a7e4-0c078731123d'::uuid,'MARINES',NULL,true,now(),now()), + ('50d675ab-4064-4edb-8f1d-5739b0318ed9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'b0422b13-4afe-443e-901f-fe652cde23a4'::uuid,'MARINES',NULL,true,now(),now()), + ('a3733567-2b57-4f12-9390-967e04bc1453'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ecbc1d89-9cf6-4f52-b453-3ba473a0ff4e'::uuid,'MARINES',NULL,true,now(),now()), + ('6a321494-cdd8-4372-90a1-6a6c67f4e220'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4e85cb86-e9dd-4c7c-9677-e0a327ac895c'::uuid,'MARINES',NULL,true,now(),now()), + ('99d37d3c-be31-4d3e-9c5e-c9d816a46014'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'7f9dd10d-100e-4252-9786-706349f456ca'::uuid,'MARINES',NULL,true,now(),now()), + ('e9b4c884-ad7f-4c1a-8815-05353834f5c3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5451f8d7-60c5-4e22-bbf6-d9af8e6ace54'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('cfaa046e-6be5-4178-a451-d368317ecb86'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'9e9cba85-7c39-4836-809d-70b54baf392e'::uuid,'MARINES',NULL,true,now(),now()), + ('9b509efb-12d9-42aa-a85a-ffb026866b56'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f7470914-cf48-43be-b431-a3ca2fe5b290'::uuid,'MARINES',NULL,true,now(),now()), + ('7e54d995-b7bd-457c-bd97-0fd76891402e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'5a0d3cc1-b866-4bde-b67f-78d565facf3e'::uuid,'MARINES',NULL,true,now(),now()), + ('1357aadd-b420-42c4-8a39-bab8027fa910'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e629b95a-ec5b-4fc4-897f-e0d1050e1ec6'::uuid,'MARINES',NULL,true,now(),now()), + ('56fbbf0f-e819-41dd-802d-4e677aecd1c9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d68a626f-935a-4eb1-ba9b-6829feeff91c'::uuid,'MARINES',NULL,true,now(),now()), + ('bfc2dc53-896f-4f29-92c7-9a7a392b22f2'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ed496f6e-fd34-48d1-8586-63a1d305c49c'::uuid,'MARINES',NULL,true,now(),now()), + ('d015e8b1-86ea-489f-979d-458ae35ae8d6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'153b62b2-b1b8-4b9d-afa5-53df4150aba4'::uuid,'MARINES',NULL,true,now(),now()), + ('1f32e712-8b5e-4ae4-b409-c5c92337aed8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0020441b-bc0c-436e-be05-b997ca6a853c'::uuid,'MARINES',NULL,true,now(),now()), + ('a8a85e00-e657-41a2-8f32-84bdd9c92ec8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a8ae9bb9-e9ac-49b4-81dc-336b8a0dcb54'::uuid,'MARINES',NULL,true,now(),now()), + ('4ad1a57f-0e9e-4405-9a08-0ffa211fc8ce'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1aa43046-8d6b-4249-88dc-b259d86c0cb8'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('dd765820-ffa5-4673-a347-fbe3464cd2d8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'84b50723-95fc-41d1-8115-a734c7e53f66'::uuid,'MARINES',NULL,true,now(),now()), + ('6eff7586-59bd-4638-809b-5cc346646dc9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'63dc3f78-235e-4b1c-b1db-459d7f5ae25f'::uuid,'MARINES',NULL,true,now(),now()), + ('428b0d7a-3848-4882-a5cc-80d5ae3500d6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4bd4c579-c163-4b1b-925a-d852d5a12642'::uuid,'MARINES',NULL,true,now(),now()), + ('9f8311f3-e191-4383-8fb8-2b58cd545dd4'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ce7f1fc9-5b94-43cb-b398-b31cb6350d6a'::uuid,'MARINES',NULL,true,now(),now()), + ('81e3e6fe-7db3-49ff-b18c-8b078e3d129e'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4a6a3260-e1ec-4d78-8c07-d89f1405ca16'::uuid,'MARINES',NULL,true,now(),now()), + ('4cf1c40f-60f0-4a47-a351-471720ba0fd3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'658274b5-720c-4a70-ba9d-249614d85ebc'::uuid,'MARINES',NULL,true,now(),now()), + ('0754978b-d11e-4f2c-b59c-3252d2735b26'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'41f0736c-6d26-4e93-9668-860e9f0e222a'::uuid,'MARINES',NULL,true,now(),now()), + ('c9b8305d-2e16-46a7-9b7c-b3edeb6f8e93'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'c2a8e8c3-dddc-4c0f-a23a-0b4e2c20af0d'::uuid,'MARINES',NULL,true,now(),now()), + ('a8768e6d-1a6d-449a-9f2e-2e198dcd6e00'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'0f1e1c87-0497-4ee2-970d-21ac2d2155db'::uuid,'MARINES',NULL,true,now(),now()), + ('cf292129-d543-4632-9cb3-b074279e42be'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e40b411d-55f0-4470-83d0-0bbe11fa77dd'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('3f07cedf-ad90-465e-95a5-ce44a2f088b8'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'2632b4e5-c6cb-4e64-8924-0b7e4b1115ec'::uuid,'MARINES',NULL,true,now(),now()), + ('42a2d93b-9dea-4c63-b0a7-c39364aacf75'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1336deb9-5c87-409d-8051-4ab9f211eb29'::uuid,'MARINES',NULL,true,now(),now()), + ('64fe0d14-98f7-4f73-9aa3-a19617b2d8c3'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'7a6d3b5b-81a6-4db5-b2ab-ecbfd6bd7941'::uuid,'MARINES',NULL,true,now(),now()), + ('3ab04740-9f13-47f8-a80e-b63ab5b67590'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'91b69254-5976-4839-a31d-972e9958d9cf'::uuid,'MARINES',NULL,true,now(),now()), + ('3be8e483-6bce-4a7d-a3bd-fc1485e79818'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'166f3629-79b9-451a-90a3-c43680929a2f'::uuid,'MARINES',NULL,true,now(),now()), + ('ddf69dcb-345e-47c1-a585-ce24d0854de5'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'4fe05eb4-1b1c-4d4a-a185-0b039ac64835'::uuid,'MARINES',NULL,true,now(),now()), + ('fe9e365f-98a5-4658-a58d-5f8279ff3e5a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'ca8aecda-4642-45c7-96ed-309c35c4b78f'::uuid,'MARINES',NULL,true,now(),now()), + ('2051a441-f4d0-4b6e-8614-74761de505e6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'e4bc9404-5466-4a41-993e-09474266afc3'::uuid,'MARINES',NULL,true,now(),now()), + ('6797daed-f002-431c-829b-dab7c1b16ff2'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'d4a51d90-3945-4ad3-9cba-a18d8d7b34d7'::uuid,'MARINES',NULL,true,now(),now()), + ('2398bf11-1986-4914-8e47-6afac423283a'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'a5a60d63-d9a8-4bde-9081-f011784b2d31'::uuid,'MARINES',NULL,true,now(),now()); +INSERT INTO gbloc_aors (id,jppso_regions_id,oconus_rate_area_id,department_indicator,shipment_type,is_active,created_at,updated_at) VALUES + ('f3a6c247-4c4c-4f45-9162-50307d4711f5'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'93842d74-1f3e-46cd-aca9-9f0dafbd20a1'::uuid,'MARINES',NULL,true,now(),now()), + ('0a82b196-7c24-4214-9155-05f0c5c2d7e9'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'1bc0dbda-f0ce-4b76-a551-78dbaaa9e3ec'::uuid,'MARINES',NULL,true,now(),now()), + ('af0a2db3-2e2e-4a78-804b-9a8b89b96e12'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'f1a7ef90-cfa6-4e0c-92c3-f8d70c07ba4d'::uuid,'MARINES',NULL,true,now(),now()), + ('5205a965-d424-469a-9526-17ef551685e6'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'9c5b4c4d-e05c-42ca-bd77-b61f5d8c7afc'::uuid,'MARINES',NULL,true,now(),now()), + ('f263fdb0-933b-42a7-925e-a9852c5804fa'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'27ec2576-78dd-4605-b1a8-0b9ca207fc26'::uuid,'MARINES',NULL,true,now(),now()), + ('b03c7ae3-4d6d-445c-b94a-73af723e5226'::uuid,'85b324ae-1a0d-4f7d-971f-ea509dcc73d7'::uuid,'12396ebc-59e9-430a-8475-759a38af6b7a'::uuid,'MARINES',NULL,true,now(),now()); + + +drop view move_to_gbloc; +CREATE OR REPLACE VIEW move_to_gbloc AS +SELECT move_id, gbloc FROM ( + SELECT DISTINCT ON (sh.move_id) sh.move_id, s.affiliation, + COALESCE(pctg.gbloc, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + FROM mto_shipments sh + JOIN moves m ON sh.move_id = m.id + JOIN orders o on m.orders_id = o.id + JOIN service_members s on o.service_member_id = s.id + LEFT JOIN ( SELECT a.id AS address_id, + pctg_1.gbloc, pctg_1.postal_code + FROM addresses a + JOIN postal_code_to_gblocs pctg_1 ON a.postal_code::text = pctg_1.postal_code::text) pctg ON pctg.address_id = sh.pickup_address_id + LEFT JOIN ( SELECT ppm.shipment_id, + pctg_1.gbloc + FROM ppm_shipments ppm + JOIN addresses ppm_address ON ppm.pickup_postal_address_id = ppm_address.id + JOIN postal_code_to_gblocs pctg_1 ON ppm_address.postal_code::text = pctg_1.postal_code::text) pctg_ppm ON pctg_ppm.shipment_id = sh.id + LEFT JOIN ( SELECT a.id AS address_id, + cast(jr.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions jr ON ga.jppso_regions_id = jr.id + ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.pickup_address_id + and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' + when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' + else s.affiliation + end = pctg_oconus_bos.department_indicator + LEFT JOIN ( SELECT a.id AS address_id, + cast(pctg_1.code as varchar) AS gbloc, ga.department_indicator + FROM addresses a + JOIN re_oconus_rate_areas ora ON a.us_post_region_cities_id = ora.us_post_region_cities_id + JOIN gbloc_aors ga ON ora.id = ga.oconus_rate_area_id + JOIN jppso_regions pctg_1 ON ga.jppso_regions_id = pctg_1.id + ) pctg_oconus ON pctg_oconus.address_id = sh.pickup_address_id and pctg_oconus.department_indicator is null + WHERE sh.deleted_at IS NULL + ORDER BY sh.move_id, sh.created_at) as m; + + CREATE OR REPLACE VIEW move_to_dest_gbloc AS SELECT distinct move_id, gbloc FROM ( @@ -25,8 +232,6 @@ SELECT distinct move_id, gbloc FROM ( ) pctg_oconus_bos ON pctg_oconus_bos.address_id = sh.destination_address_id and case when s.affiliation = 'AIR_FORCE' THEN 'AIR_AND_SPACE_FORCE' when s.affiliation = 'SPACE_FORCE' THEN 'AIR_AND_SPACE_FORCE' - when s.affiliation = 'NAVY' THEN 'NAVY_AND_MARINES' - when s.affiliation = 'MARINES' THEN 'NAVY_AND_MARINES' else s.affiliation end = pctg_oconus_bos.department_indicator LEFT JOIN ( SELECT a.id AS address_id, @@ -112,18 +317,24 @@ BEGIN ) )::JSONB AS orders, COALESCE( - json_agg( - json_build_object( - ''id'', mto_shipments.id, - ''shipment_type'', mto_shipments.shipment_type, - ''status'', mto_shipments.status, - ''requested_pickup_date'', TO_CHAR(mto_shipments.requested_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), - ''scheduled_pickup_date'', TO_CHAR(mto_shipments.scheduled_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), - ''requested_delivery_date'', TO_CHAR(mto_shipments.requested_delivery_date, ''YYYY-MM-DD"T00:00:00Z"''), - ''approved_date'', TO_CHAR(mto_shipments.approved_date, ''YYYY-MM-DD"T00:00:00Z"''), - ''prime_estimated_weight'', mto_shipments.prime_estimated_weight + ( + SELECT json_agg( + json_build_object( + ''id'', ms.id, + ''shipment_type'', ms.shipment_type, + ''status'', ms.status, + ''requested_pickup_date'', TO_CHAR(ms.requested_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''scheduled_pickup_date'', TO_CHAR(ms.scheduled_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''approved_date'', TO_CHAR(ms.approved_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''prime_estimated_weight'', ms.prime_estimated_weight + ) ) - ) FILTER (WHERE mto_shipments.id IS NOT NULL), + FROM ( + SELECT DISTINCT ON (mto_shipments.id) mto_shipments.* + FROM mto_shipments + WHERE mto_shipments.move_id = moves.id + ) AS ms + ), ''[]'' )::JSONB AS mto_shipments, json_build_object( @@ -152,19 +363,8 @@ BEGIN WHERE moves.show = TRUE '; - -- add destination queue-specific filters (pending dest address requests, dest SIT & shuttle service items) - sql_query := sql_query || ' - AND ( - shipment_address_updates.status = ''REQUESTED'' - OR ( - mto_service_items.status = ''SUBMITTED'' - AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSHUT'', ''DDSFSC'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSHUT'') - ) - ) - '; - IF user_gbloc IS NOT NULL THEN - sql_query := sql_query || ' AND move_to_gbloc.gbloc = $1 '; + sql_query := sql_query || ' AND move_to_dest_gbloc.gbloc = $1 '; END IF; IF customer_name IS NOT NULL THEN @@ -218,6 +418,17 @@ BEGIN sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%'' || $12 || ''%'' '; END IF; + -- add destination queue-specific filters (pending dest address requests, dest SIT & shuttle service items) + sql_query := sql_query || ' + AND ( + shipment_address_updates.status = ''REQUESTED'' + OR ( + mto_service_items.status = ''SUBMITTED'' + AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSHUT'', ''DDSFSC'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSHUT'') + ) + ) + '; + sql_query := sql_query || ' GROUP BY moves.id, diff --git a/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx b/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx index 44b11a5567d..11094276bba 100644 --- a/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx +++ b/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx @@ -609,7 +609,7 @@ const ServicesCounselingQueue = ({ return ; }; - if (queueType === 'Search') { + if (queueType === 'search') { return (
{renderNavBar()} From 711252076cc756a240ccfed7bf32ebd422787547 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 4 Feb 2025 22:19:22 +0000 Subject: [PATCH 07/21] dear gawd I think I have it working - need tests --- ...nation_queue_db_func_and_gbloc_view.up.sql | 48 +++++++++++++++++-- pkg/services/order/order_fetcher.go | 8 ++-- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql index bd09ad533c4..8aabdaeddf0 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -205,11 +205,12 @@ SELECT move_id, gbloc FROM ( ORDER BY sh.move_id, sh.created_at) as m; +-- used for the destination queue CREATE OR REPLACE VIEW move_to_dest_gbloc AS SELECT distinct move_id, gbloc FROM ( SELECT sh.move_id, s.affiliation, - COALESCE(pctg.gbloc, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc + COALESCE(case when s.affiliation = 'MARINES' then 'USMC' else pctg.gbloc end, coalesce(pctg_oconus_bos.gbloc, coalesce(pctg_oconus.gbloc, pctg_ppm.gbloc))) AS gbloc FROM mto_shipments sh JOIN moves m ON sh.move_id = m.id JOIN orders o on m.orders_id = o.id @@ -244,7 +245,7 @@ SELECT distinct move_id, gbloc FROM ( WHERE sh.deleted_at IS NULL) as m; -- database function that returns a list of moves that have destination requests --- this includes shipment address update requests & destination service items +-- this includes shipment address update requests, destination SIT, & destination shuttle CREATE OR REPLACE FUNCTION get_destination_queue( user_gbloc TEXT DEFAULT NULL, customer_name TEXT DEFAULT NULL, @@ -259,7 +260,9 @@ CREATE OR REPLACE FUNCTION get_destination_queue( counseling_office TEXT DEFAULT NULL, too_assigned_user TEXT DEFAULT NULL, page INTEGER DEFAULT 1, - per_page INTEGER DEFAULT 20 + per_page INTEGER DEFAULT 20, + sort TEXT DEFAULT NULL, + sort_direction TEXT DEFAULT NULL ) RETURNS TABLE ( id UUID, @@ -279,6 +282,8 @@ RETURNS TABLE ( DECLARE sql_query TEXT; offset_value INTEGER; + sort_column TEXT; + sort_order TEXT; BEGIN IF page < 1 THEN page := 1; @@ -418,7 +423,7 @@ BEGIN sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%'' || $12 || ''%'' '; END IF; - -- add destination queue-specific filters (pending dest address requests, dest SIT & shuttle service items) + -- add destination queue-specific filters (pending dest address requests, dest SIT & dest shuttle service items) sql_query := sql_query || ' AND ( shipment_address_updates.status = ''REQUESTED'' @@ -429,6 +434,36 @@ BEGIN ) '; + -- default sorting values if none are provided (move.id) + sort_column := 'id'; + sort_order := 'ASC'; + + IF sort IS NOT NULL THEN + CASE sort + WHEN 'locator' THEN sort_column := 'moves.locator'; + WHEN 'status' THEN sort_column := 'moves.status'; + WHEN 'customerName' THEN sort_column := 'service_members.last_name'; + WHEN 'edipi' THEN sort_column := 'service_members.edipi'; + WHEN 'emplid' THEN sort_column := 'service_members.emplid'; + WHEN 'requestedMoveDate' THEN sort_column := 'COALESCE(mto_shipments.requested_pickup_date, ppm_shipments.expected_departure_date, mto_shipments.requested_delivery_date)'; + WHEN 'appearedInTooAt' THEN sort_column := 'COALESCE(moves.submitted_at, moves.approvals_requested_at)'; + WHEN 'branch' THEN sort_column := 'service_members.affiliation'; + WHEN 'originDutyLocation' THEN sort_column := 'origin_duty_locations.name'; + WHEN 'counselingOffice' THEN sort_column := 'counseling_offices.name'; + WHEN 'assignedTo' THEN sort_column := 'too_user.last_name'; + ELSE + sort_column := 'moves.id'; + END CASE; + END IF; + + IF sort_direction IS NOT NULL THEN + IF LOWER(sort_direction) = 'desc' THEN + sort_order := 'DESC'; + ELSE + sort_order := 'ASC'; + END IF; + END IF; + sql_query := sql_query || ' GROUP BY moves.id, @@ -439,6 +474,9 @@ BEGIN moves.locked_by, moves.too_assigned_id, moves.counseling_transportation_office_id, + mto_shipments.requested_pickup_date, + mto_shipments.requested_delivery_date, + ppm_shipments.expected_departure_date, orders.id, service_members.id, service_members.first_name, @@ -450,7 +488,7 @@ BEGIN counseling_offices.name, too_user.first_name, too_user.last_name'; - sql_query := sql_query || ' ORDER BY moves.id ASC '; + sql_query := sql_query || format(' ORDER BY %s %s ', sort_column, sort_order); sql_query := sql_query || ' LIMIT $13 OFFSET $14 '; RETURN QUERY EXECUTE sql_query diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index 53478c9860d..b0e59912f39 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -348,7 +348,7 @@ func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext } // calling the database function with all passed in parameters - err := appCtx.DB().RawQuery("SELECT * FROM get_destination_queue($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)", + err := appCtx.DB().RawQuery("SELECT * FROM get_destination_queue($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)", officeUserGbloc, params.CustomerName, params.Edipi, @@ -356,13 +356,15 @@ func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext pq.Array(params.Status), params.Locator, params.RequestedMoveDate, - params.SubmittedAt, + params.AppearedInTOOAt, params.Branch, strings.Join(params.OriginDutyLocation, " "), params.CounselingOffice, params.TOOAssignedUser, params.Page, - params.PerPage). + params.PerPage, + params.Sort, + params.Order). All(&movesWithCount) if err != nil { From df78bf31aa5dc7482904cc236b8e07dad2948729 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 4 Feb 2025 22:48:25 +0000 Subject: [PATCH 08/21] cleanup before adding tests --- pkg/gen/ghcapi/embedded_spec.go | 32 ++--------- .../queues/get_destination_requests_queue.go | 4 +- ...t_destination_requests_queue_parameters.go | 55 ------------------- ...t_destination_requests_queue_urlbuilder.go | 18 ------ pkg/handlers/ghcapi/queues.go | 18 ++---- pkg/services/order/order_fetcher.go | 22 +++----- src/pages/Office/MoveQueue/MoveQueue.test.jsx | 3 +- .../ServicesCounselingQueue.jsx | 2 +- swagger-def/ghc.yaml | 13 +---- swagger/ghc.yaml | 22 ++------ 10 files changed, 32 insertions(+), 157 deletions(-) diff --git a/pkg/gen/ghcapi/embedded_spec.go b/pkg/gen/ghcapi/embedded_spec.go index 221fa8971bd..0704324506f 100644 --- a/pkg/gen/ghcapi/embedded_spec.go +++ b/pkg/gen/ghcapi/embedded_spec.go @@ -4678,14 +4678,14 @@ func init() { }, "/queues/destination-requests": { "get": { - "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved.\n", + "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO.\n", "produces": [ "application/json" ], "tags": [ "queues" ], - "summary": "Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests)", + "summary": "Gets queued list of all customer moves by GBLOC that have both CONUS \u0026 OCONUS destination requests (destination SIT, destination shuttle, address requests)", "operationId": "getDestinationRequestsQueue", "parameters": [ { @@ -4797,18 +4797,6 @@ func init() { "name": "status", "in": "query" }, - { - "type": "string", - "description": "order type", - "name": "orderType", - "in": "query" - }, - { - "type": "string", - "description": "Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role.\n", - "name": "viewAsGBLOC", - "in": "query" - }, { "type": "string", "description": "Used to illustrate which user is assigned to this move.\n", @@ -21506,14 +21494,14 @@ func init() { }, "/queues/destination-requests": { "get": { - "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved.\n", + "description": "A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO.\n", "produces": [ "application/json" ], "tags": [ "queues" ], - "summary": "Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests)", + "summary": "Gets queued list of all customer moves by GBLOC that have both CONUS \u0026 OCONUS destination requests (destination SIT, destination shuttle, address requests)", "operationId": "getDestinationRequestsQueue", "parameters": [ { @@ -21625,18 +21613,6 @@ func init() { "name": "status", "in": "query" }, - { - "type": "string", - "description": "order type", - "name": "orderType", - "in": "query" - }, - { - "type": "string", - "description": "Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role.\n", - "name": "viewAsGBLOC", - "in": "query" - }, { "type": "string", "description": "Used to illustrate which user is assigned to this move.\n", diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go index f4fdf4135d3..0bc440cf200 100644 --- a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue.go @@ -32,9 +32,9 @@ func NewGetDestinationRequestsQueue(ctx *middleware.Context, handler GetDestinat /* GetDestinationRequestsQueue swagger:route GET /queues/destination-requests queues getDestinationRequestsQueue -Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests) +Gets queued list of all customer moves by GBLOC that have both CONUS & OCONUS destination requests (destination SIT, destination shuttle, address requests) -A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved. +A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO. */ type GetDestinationRequestsQueue struct { Context *middleware.Context diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go index 86930ef5fab..dac60111a5d 100644 --- a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_parameters.go @@ -75,10 +75,6 @@ type GetDestinationRequestsQueueParams struct { In: query */ Order *string - /*order type - In: query - */ - OrderType *string /* Unique: true In: query @@ -106,11 +102,6 @@ type GetDestinationRequestsQueueParams struct { In: query */ Status []string - /*Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role. - - In: query - */ - ViewAsGBLOC *string } // BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface @@ -174,11 +165,6 @@ func (o *GetDestinationRequestsQueueParams) BindRequest(r *http.Request, route * res = append(res, err) } - qOrderType, qhkOrderType, _ := qs.GetOK("orderType") - if err := o.bindOrderType(qOrderType, qhkOrderType, route.Formats); err != nil { - res = append(res, err) - } - qOriginDutyLocation, qhkOriginDutyLocation, _ := qs.GetOK("originDutyLocation") if err := o.bindOriginDutyLocation(qOriginDutyLocation, qhkOriginDutyLocation, route.Formats); err != nil { res = append(res, err) @@ -208,11 +194,6 @@ func (o *GetDestinationRequestsQueueParams) BindRequest(r *http.Request, route * if err := o.bindStatus(qStatus, qhkStatus, route.Formats); err != nil { res = append(res, err) } - - qViewAsGBLOC, qhkViewAsGBLOC, _ := qs.GetOK("viewAsGBLOC") - if err := o.bindViewAsGBLOC(qViewAsGBLOC, qhkViewAsGBLOC, route.Formats); err != nil { - res = append(res, err) - } if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -432,24 +413,6 @@ func (o *GetDestinationRequestsQueueParams) validateOrder(formats strfmt.Registr return nil } -// bindOrderType binds and validates parameter OrderType from query. -func (o *GetDestinationRequestsQueueParams) bindOrderType(rawData []string, hasKey bool, formats strfmt.Registry) error { - var raw string - if len(rawData) > 0 { - raw = rawData[len(rawData)-1] - } - - // Required: false - // AllowEmptyValue: false - - if raw == "" { // empty values pass all other validations - return nil - } - o.OrderType = &raw - - return nil -} - // bindOriginDutyLocation binds and validates array parameter OriginDutyLocation from query. // // Arrays are parsed according to CollectionFormat: "multi" (defaults to "csv" when empty). @@ -624,21 +587,3 @@ func (o *GetDestinationRequestsQueueParams) validateStatus(formats strfmt.Regist } return nil } - -// bindViewAsGBLOC binds and validates parameter ViewAsGBLOC from query. -func (o *GetDestinationRequestsQueueParams) bindViewAsGBLOC(rawData []string, hasKey bool, formats strfmt.Registry) error { - var raw string - if len(rawData) > 0 { - raw = rawData[len(rawData)-1] - } - - // Required: false - // AllowEmptyValue: false - - if raw == "" { // empty values pass all other validations - return nil - } - o.ViewAsGBLOC = &raw - - return nil -} diff --git a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go index c267cfe2aa8..c8b86e869dc 100644 --- a/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go +++ b/pkg/gen/ghcapi/ghcoperations/queues/get_destination_requests_queue_urlbuilder.go @@ -26,14 +26,12 @@ type GetDestinationRequestsQueueURL struct { Emplid *string Locator *string Order *string - OrderType *string OriginDutyLocation []string Page *int64 PerPage *int64 RequestedMoveDate *string Sort *string Status []string - ViewAsGBLOC *string _basePath string // avoid unkeyed usage @@ -149,14 +147,6 @@ func (o *GetDestinationRequestsQueueURL) Build() (*url.URL, error) { qs.Set("order", orderQ) } - var orderTypeQ string - if o.OrderType != nil { - orderTypeQ = *o.OrderType - } - if orderTypeQ != "" { - qs.Set("orderType", orderTypeQ) - } - var originDutyLocationIR []string for _, originDutyLocationI := range o.OriginDutyLocation { originDutyLocationIS := originDutyLocationI @@ -220,14 +210,6 @@ func (o *GetDestinationRequestsQueueURL) Build() (*url.URL, error) { } } - var viewAsGBLOCQ string - if o.ViewAsGBLOC != nil { - viewAsGBLOCQ = *o.ViewAsGBLOC - } - if viewAsGBLOCQ != "" { - qs.Set("viewAsGBLOC", viewAsGBLOCQ) - } - _result.RawQuery = qs.Encode() return &_result, nil diff --git a/pkg/handlers/ghcapi/queues.go b/pkg/handlers/ghcapi/queues.go index 8e779d1123f..f4b124cbb1c 100644 --- a/pkg/handlers/ghcapi/queues.go +++ b/pkg/handlers/ghcapi/queues.go @@ -191,9 +191,9 @@ func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationR return h.AuditableAppContextFromRequestWithErrors(params.HTTPRequest, func(appCtx appcontext.AppContext) (middleware.Responder, error) { if !appCtx.Session().IsOfficeUser() || - (!appCtx.Session().Roles.HasRole(roles.RoleTypeTOO) && !appCtx.Session().Roles.HasRole(roles.RoleTypeHQ)) { + (!appCtx.Session().Roles.HasRole(roles.RoleTypeTOO)) { forbiddenErr := apperror.NewForbiddenError( - "user is not authenticated with TOO or HQ office role", + "user is not authenticated with TOO role", ) appCtx.Logger().Error(forbiddenErr.Error()) return queues.NewGetDestinationRequestsQueueForbidden(), forbiddenErr @@ -214,28 +214,23 @@ func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationR PerPage: params.PerPage, Sort: params.Sort, Order: params.Order, - OrderType: params.OrderType, TOOAssignedUser: params.AssignedTo, CounselingOffice: params.CounselingOffice, } + // we only care about moves in APPROVALS REQUESTED status if params.Status == nil { ListOrderParams.Status = []string{string(models.MoveStatusAPPROVALSREQUESTED)} } - // Let's set default values for page and perPage if we don't get arguments for them. We'll use 1 for page and 20 for perPage. + // default pagination values if params.Page == nil { ListOrderParams.Page = models.Int64Pointer(1) } - // Same for perPage if params.PerPage == nil { ListOrderParams.PerPage = models.Int64Pointer(20) } - if params.ViewAsGBLOC != nil && appCtx.Session().Roles.HasRole(roles.RoleTypeHQ) { - ListOrderParams.ViewAsGBLOC = params.ViewAsGBLOC - } - moves, count, err := h.OrderFetcher.ListDestinationRequestsOrders( appCtx, appCtx.Session().OfficeUserID, @@ -244,7 +239,7 @@ func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationR ) if err != nil { appCtx.Logger(). - Error("error fetching list of moves for office user", zap.Error(err)) + Error("error fetching destinaton queue for office user", zap.Error(err)) return queues.NewGetDestinationRequestsQueueInternalServerError(), err } @@ -269,7 +264,7 @@ func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationR return queues.NewGetDestinationRequestsQueueInternalServerError(), err } - // if the TOO/office user is accessing the queue, we need to unlock move/moves they have locked + // if the TOO is accessing the queue, we need to unlock move/moves they have locked if appCtx.Session().IsOfficeUser() { officeUserID := appCtx.Session().OfficeUserID for i, move := range moves { @@ -283,7 +278,6 @@ func (h GetDestinationRequestsQueueHandler) Handle(params queues.GetDestinationR moves[i] = *unlockedMove } } - // checking if moves that are NOT in their queue are locked by the user (using search, etc) err := h.CheckForLockedMovesAndUnlock(appCtx, officeUserID) if err != nil { appCtx.Logger().Error(fmt.Sprintf("failed to unlock moves for office user ID: %s", officeUserID), zap.Error(err)) diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go index b0e59912f39..500cdbad41f 100644 --- a/pkg/services/order/order_fetcher.go +++ b/pkg/services/order/order_fetcher.go @@ -310,6 +310,7 @@ func (f orderFetcher) ListOrders(appCtx appcontext.AppContext, officeUserID uuid return moves, count, nil } +// this is a custom/temporary struct used in the below service object to get destination queue moves type MoveWithCount struct { models.Move OrdersRaw json.RawMessage `json:"orders" db:"orders"` @@ -335,16 +336,10 @@ func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext var movesWithCount []MoveWithCount // getting the office user's GBLOC - var officeUserGbloc string - if params.ViewAsGBLOC != nil { - officeUserGbloc = *params.ViewAsGBLOC - } else { - var gblocErr error - gblocFetcher := officeuser.NewOfficeUserGblocFetcher() - officeUserGbloc, gblocErr = gblocFetcher.FetchGblocForOfficeUser(appCtx, officeUserID) - if gblocErr != nil { - return []models.Move{}, 0, gblocErr - } + gblocFetcher := officeuser.NewOfficeUserGblocFetcher() + officeUserGbloc, gblocErr := gblocFetcher.FetchGblocForOfficeUser(appCtx, officeUserID) + if gblocErr != nil { + return []models.Move{}, 0, gblocErr } // calling the database function with all passed in parameters @@ -371,7 +366,7 @@ func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext return []models.Move{}, 0, err } - // each row is sent back with the total count, so we will take the value from the first one + // each row is sent back with the total count from the db func, so we will take the value from the first one var count int64 if len(movesWithCount) > 0 { count = movesWithCount[0].TotalCount @@ -414,11 +409,12 @@ func (f orderFetcher) ListDestinationRequestsOrders(appCtx appcontext.AppContext movesWithCount[i].TOOAssignedUser = &tooAssigned } - // the handler consumes a Move object, so we have to copy our custom struct into the Move struct + // the handler consumes a Move object and NOT the MoveWithCount struct used in this func + // so we have to copy our custom struct into the Move struct for _, moveWithCount := range movesWithCount { var move models.Move if err := copier.Copy(&move, &moveWithCount); err != nil { - return nil, 0, fmt.Errorf("error copying movesWithCount into Moves: %w", err) + return nil, 0, fmt.Errorf("error copying movesWithCount into Moves struct: %w", err) } moves = append(moves, move) } diff --git a/src/pages/Office/MoveQueue/MoveQueue.test.jsx b/src/pages/Office/MoveQueue/MoveQueue.test.jsx index 4e5ec01cd33..87defd030a8 100644 --- a/src/pages/Office/MoveQueue/MoveQueue.test.jsx +++ b/src/pages/Office/MoveQueue/MoveQueue.test.jsx @@ -328,7 +328,7 @@ describe('MoveQueue', () => { wrapper.update(); expect(wrapper.find('[data-testid="multi-value-container"]').text()).toEqual('New move'); }); - it('renders Search and Move Queue tabs', () => { + it('renders Search, Destination Queue and Move Queue tabs', () => { reactRouterDom.useParams.mockReturnValue({ queueType: generalRoutes.QUEUE_SEARCH_PATH }); render( @@ -338,6 +338,7 @@ describe('MoveQueue', () => { expect(screen.getByTestId('closeout-tab-link')).toBeInTheDocument(); expect(screen.getByTestId('search-tab-link')).toBeInTheDocument(); expect(screen.getByText('Task Order Queue', { selector: 'span' })).toBeInTheDocument(); + expect(screen.getByText('Destination Requests Queue', { selector: 'span' })).toBeInTheDocument(); expect(screen.getByText('Search', { selector: 'span' })).toBeInTheDocument(); }); it('renders TableQueue when Search tab is selected', () => { diff --git a/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx b/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx index 11094276bba..6518eda8080 100644 --- a/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx +++ b/src/pages/Office/ServicesCounselingQueue/ServicesCounselingQueue.jsx @@ -609,7 +609,7 @@ const ServicesCounselingQueue = ({ return ; }; - if (queueType === 'search') { + if (queueType === generalRoutes.QUEUE_SEARCH_PATH) { return (
{renderNavBar()} diff --git a/swagger-def/ghc.yaml b/swagger-def/ghc.yaml index 7ed8e6f8cdc..4437679cf39 100644 --- a/swagger-def/ghc.yaml +++ b/swagger-def/ghc.yaml @@ -3739,9 +3739,9 @@ paths: get: produces: - application/json - summary: Gets queued list of all customer moves by GBLOC that have destination requests (destination SIT, shuttle, address requests) + summary: Gets queued list of all customer moves by GBLOC that have both CONUS & OCONUS destination requests (destination SIT, destination shuttle, address requests) description: > - A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items (including shuttle) and destination address requests that are not approved. + A TOO will view this queue when they have destination requests tied to their GBLOC. This includes unapproved destination SIT service items, destination shuttle service items and destination address requests that are not yet approved by the TOO. operationId: getDestinationRequestsQueue tags: - queues @@ -3822,15 +3822,6 @@ paths: - SUBMITTED - SERVICE COUNSELING COMPLETED - APPROVALS REQUESTED - - in: query - name: orderType - type: string - description: order type - - in: query - name: viewAsGBLOC - type: string - description: | - Used to return a queue for a GBLOC other than the default of the current user. Requires the HQ role. The parameter is ignored if the requesting user does not have the necessary role. - in: query name: assignedTo type: string diff --git a/swagger/ghc.yaml b/swagger/ghc.yaml index ce3f29058b9..7b507636923 100644 --- a/swagger/ghc.yaml +++ b/swagger/ghc.yaml @@ -3906,13 +3906,14 @@ paths: produces: - application/json summary: >- - Gets queued list of all customer moves by GBLOC that have destination - requests (destination SIT, shuttle, address requests) + Gets queued list of all customer moves by GBLOC that have both CONUS & + OCONUS destination requests (destination SIT, destination shuttle, + address requests) description: > A TOO will view this queue when they have destination requests tied to - their GBLOC. This includes unapproved destination SIT service items - (including shuttle) and destination address requests that are not - approved. + their GBLOC. This includes unapproved destination SIT service items, + destination shuttle service items and destination address requests that + are not yet approved by the TOO. operationId: getDestinationRequestsQueue tags: - queues @@ -3993,17 +3994,6 @@ paths: - SUBMITTED - SERVICE COUNSELING COMPLETED - APPROVALS REQUESTED - - in: query - name: orderType - type: string - description: order type - - in: query - name: viewAsGBLOC - type: string - description: > - Used to return a queue for a GBLOC other than the default of the - current user. Requires the HQ role. The parameter is ignored if the - requesting user does not have the necessary role. - in: query name: assignedTo type: string From 0aa8ab6cebb821d4d7bab26bf6cd040b26eea32f Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 4 Feb 2025 22:52:59 +0000 Subject: [PATCH 09/21] are you mocking me? --- pkg/services/mocks/WeightAllotmentFetcher.go | 117 +++++++++++++++++++ pkg/services/mocks/WeightRestrictor.go | 89 ++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 pkg/services/mocks/WeightAllotmentFetcher.go create mode 100644 pkg/services/mocks/WeightRestrictor.go diff --git a/pkg/services/mocks/WeightAllotmentFetcher.go b/pkg/services/mocks/WeightAllotmentFetcher.go new file mode 100644 index 00000000000..fa36bfbee2e --- /dev/null +++ b/pkg/services/mocks/WeightAllotmentFetcher.go @@ -0,0 +1,117 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + appcontext "github.com/transcom/mymove/pkg/appcontext" + internalmessages "github.com/transcom/mymove/pkg/gen/internalmessages" + + mock "github.com/stretchr/testify/mock" + + models "github.com/transcom/mymove/pkg/models" +) + +// WeightAllotmentFetcher is an autogenerated mock type for the WeightAllotmentFetcher type +type WeightAllotmentFetcher struct { + mock.Mock +} + +// GetAllWeightAllotments provides a mock function with given fields: appCtx +func (_m *WeightAllotmentFetcher) GetAllWeightAllotments(appCtx appcontext.AppContext) (map[internalmessages.OrderPayGrade]models.WeightAllotment, error) { + ret := _m.Called(appCtx) + + if len(ret) == 0 { + panic("no return value specified for GetAllWeightAllotments") + } + + var r0 map[internalmessages.OrderPayGrade]models.WeightAllotment + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext) (map[internalmessages.OrderPayGrade]models.WeightAllotment, error)); ok { + return rf(appCtx) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext) map[internalmessages.OrderPayGrade]models.WeightAllotment); ok { + r0 = rf(appCtx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[internalmessages.OrderPayGrade]models.WeightAllotment) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext) error); ok { + r1 = rf(appCtx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetWeightAllotment provides a mock function with given fields: appCtx, grade, ordersType +func (_m *WeightAllotmentFetcher) GetWeightAllotment(appCtx appcontext.AppContext, grade string, ordersType internalmessages.OrdersType) (models.WeightAllotment, error) { + ret := _m.Called(appCtx, grade, ordersType) + + if len(ret) == 0 { + panic("no return value specified for GetWeightAllotment") + } + + var r0 models.WeightAllotment + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, internalmessages.OrdersType) (models.WeightAllotment, error)); ok { + return rf(appCtx, grade, ordersType) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, string, internalmessages.OrdersType) models.WeightAllotment); ok { + r0 = rf(appCtx, grade, ordersType) + } else { + r0 = ret.Get(0).(models.WeightAllotment) + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, string, internalmessages.OrdersType) error); ok { + r1 = rf(appCtx, grade, ordersType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetWeightAllotmentByOrdersType provides a mock function with given fields: appCtx, ordersType +func (_m *WeightAllotmentFetcher) GetWeightAllotmentByOrdersType(appCtx appcontext.AppContext, ordersType internalmessages.OrdersType) (models.WeightAllotment, error) { + ret := _m.Called(appCtx, ordersType) + + if len(ret) == 0 { + panic("no return value specified for GetWeightAllotmentByOrdersType") + } + + var r0 models.WeightAllotment + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, internalmessages.OrdersType) (models.WeightAllotment, error)); ok { + return rf(appCtx, ordersType) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, internalmessages.OrdersType) models.WeightAllotment); ok { + r0 = rf(appCtx, ordersType) + } else { + r0 = ret.Get(0).(models.WeightAllotment) + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, internalmessages.OrdersType) error); ok { + r1 = rf(appCtx, ordersType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewWeightAllotmentFetcher creates a new instance of WeightAllotmentFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewWeightAllotmentFetcher(t interface { + mock.TestingT + Cleanup(func()) +}) *WeightAllotmentFetcher { + mock := &WeightAllotmentFetcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/services/mocks/WeightRestrictor.go b/pkg/services/mocks/WeightRestrictor.go new file mode 100644 index 00000000000..6f7ad72bae4 --- /dev/null +++ b/pkg/services/mocks/WeightRestrictor.go @@ -0,0 +1,89 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + appcontext "github.com/transcom/mymove/pkg/appcontext" + + models "github.com/transcom/mymove/pkg/models" +) + +// WeightRestrictor is an autogenerated mock type for the WeightRestrictor type +type WeightRestrictor struct { + mock.Mock +} + +// ApplyWeightRestrictionToEntitlement provides a mock function with given fields: appCtx, entitlement, weightRestriction, eTag +func (_m *WeightRestrictor) ApplyWeightRestrictionToEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, weightRestriction int, eTag string) (*models.Entitlement, error) { + ret := _m.Called(appCtx, entitlement, weightRestriction, eTag) + + if len(ret) == 0 { + panic("no return value specified for ApplyWeightRestrictionToEntitlement") + } + + var r0 *models.Entitlement + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, int, string) (*models.Entitlement, error)); ok { + return rf(appCtx, entitlement, weightRestriction, eTag) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, int, string) *models.Entitlement); ok { + r0 = rf(appCtx, entitlement, weightRestriction, eTag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Entitlement) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.Entitlement, int, string) error); ok { + r1 = rf(appCtx, entitlement, weightRestriction, eTag) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RemoveWeightRestrictionFromEntitlement provides a mock function with given fields: appCtx, entitlement, eTag +func (_m *WeightRestrictor) RemoveWeightRestrictionFromEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, eTag string) (*models.Entitlement, error) { + ret := _m.Called(appCtx, entitlement, eTag) + + if len(ret) == 0 { + panic("no return value specified for RemoveWeightRestrictionFromEntitlement") + } + + var r0 *models.Entitlement + var r1 error + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, string) (*models.Entitlement, error)); ok { + return rf(appCtx, entitlement, eTag) + } + if rf, ok := ret.Get(0).(func(appcontext.AppContext, models.Entitlement, string) *models.Entitlement); ok { + r0 = rf(appCtx, entitlement, eTag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Entitlement) + } + } + + if rf, ok := ret.Get(1).(func(appcontext.AppContext, models.Entitlement, string) error); ok { + r1 = rf(appCtx, entitlement, eTag) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewWeightRestrictor creates a new instance of WeightRestrictor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewWeightRestrictor(t interface { + mock.TestingT + Cleanup(func()) +}) *WeightRestrictor { + mock := &WeightRestrictor{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 6e0a061eb216c8e1390c888353c3f7f7fe765304 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Wed, 5 Feb 2025 15:33:00 +0000 Subject: [PATCH 10/21] added order_fetcher tests --- pkg/services/order/order_fetcher_test.go | 404 +++++++++++++++++++++++ 1 file changed, 404 insertions(+) diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index 57e85401246..653d6d7d129 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -5,6 +5,7 @@ import ( "time" "github.com/gofrs/uuid" + "github.com/stretchr/testify/mock" "github.com/transcom/mymove/pkg/auth" "github.com/transcom/mymove/pkg/factory" @@ -12,6 +13,7 @@ import ( "github.com/transcom/mymove/pkg/models/roles" "github.com/transcom/mymove/pkg/services" "github.com/transcom/mymove/pkg/services/entitlements" + "github.com/transcom/mymove/pkg/services/mocks" moveservice "github.com/transcom/mymove/pkg/services/move" officeuserservice "github.com/transcom/mymove/pkg/services/office_user" "github.com/transcom/mymove/pkg/testdatagen" @@ -2307,3 +2309,405 @@ func (suite *OrderServiceSuite) TestOriginDutyLocationFilter() { suite.Equal(locationName, string(expectedMoves[0].Orders.OriginDutyLocation.Name)) }) } + +func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() { + army := models.AffiliationARMY + airForce := models.AffiliationAIRFORCE + spaceForce := models.AffiliationSPACEFORCE + usmc := models.AffiliationMARINES + + setupTestData := func(officeUserGBLOC string) (models.OfficeUser, auth.Session) { + + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{ + { + Model: models.TransportationOffice{ + Gbloc: officeUserGBLOC, + }, + }, + }, []roles.RoleType{roles.RoleTypeTOO}) + + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "99501", officeUser.TransportationOffice.Gbloc) + + fetcher := &mocks.OfficeUserGblocFetcher{} + fetcher.On("FetchGblocForOfficeUser", + mock.AnythingOfType("*appcontext.appContext"), + officeUser.ID, + ).Return(officeUserGBLOC, nil) + + session := auth.Session{ + ApplicationName: auth.OfficeApp, + Roles: officeUser.User.Roles, + OfficeUserID: officeUser.ID, + IDToken: "fake_token", + AccessToken: "fakeAccessToken", + } + + return officeUser, session + } + + buildMoveKKFA := func() (models.Move, models.MTOShipment) { + postalCode := "90210" + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "90210", "KKFA") + + // setting up two moves, each with requested destination SIT service items + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{PostalCode: postalCode}, + }, + }, nil) + + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + return move, shipment + } + + buildMoveZone2AK := func(branch models.ServiceMemberAffiliation) (models.Move, models.MTOShipment) { + // Create a USAF move in Alaska Zone II + // this is a hard coded uuid that is a us_post_region_cities_id within AK Zone II + zone2UUID, err := uuid.FromString("66768964-e0de-41f3-b9be-7ef32e4ae2b4") + suite.FatalNoError(err) + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + City: "Anchorage", + State: "AK", + PostalCode: "99501", + UsPostRegionCityID: &zone2UUID, + }, + }, + }, nil) + + // setting up two moves, each with requested destination SIT service items + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }, + { + Model: models.ServiceMember{ + Affiliation: &branch, + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + return move, shipment + } + + buildMoveZone4AK := func(branch models.ServiceMemberAffiliation) (models.Move, models.MTOShipment) { + // Create a USAF move in Alaska Zone II + // this is a hard coded uuid that is a us_post_region_cities_id within AK Zone II + zone4UUID, err := uuid.FromString("78a6f230-9a3a-46ed-aa48-2e3decfe70ff") + suite.FatalNoError(err) + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{ + City: "Anchorage", + State: "AK", + PostalCode: "99501", + UsPostRegionCityID: &zone4UUID, + }, + }, + }, nil) + // setting up two moves, each with requested destination SIT service items + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }, + { + Model: models.ServiceMember{ + Affiliation: &branch, + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + return move, shipment + } + + waf := entitlements.NewWeightAllotmentFetcher() + orderFetcher := NewOrderFetcher(waf) + + suite.Run("returns moves for KKFA GBLOC when destination address is in KKFA GBLOC", func() { + officeUser, session := setupTestData("KKFA") + // setting up two moves, each with requested destination SIT service items + move, shipment := buildMoveKKFA() + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + move2, shipment2 := buildMoveKKFA() + + // destination shuttle + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, + ) + + suite.FatalNoError(err) + suite.Equal(2, moveCount) + suite.Len(moves, 2) + }) + + suite.Run("returns moves for MBFL GBLOC including USAF/SF in Alaska Zone II", func() { + officeUser, session := setupTestData("MBFL") + + // setting up two moves, each with requested destination SIT service items + // a move associated with an air force customer containing AK Zone II shipment + move, shipment := buildMoveZone2AK(airForce) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + // Create a move outside Alaska Zone II (Zone IV in this case) + move2, shipment2 := buildMoveZone4AK(spaceForce) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + params := services.ListOrderParams{Status: []string{string(models.MoveStatusAPPROVALSREQUESTED)}} + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, ¶ms, + ) + + // we should get both moves back because one is in Zone II & the other is within the postal code GBLOC + suite.FatalNoError(err) + suite.Equal(2, moveCount) + suite.Len(moves, 2) + }) + + suite.Run("returns moves for JEAT GBLOC excluding USAF/SF in Alaska Zone II", func() { + officeUser, session := setupTestData("JEAT") + + // Create a move in Zone II, but not an air force or space force service member + move, shipment := buildMoveZone4AK(army) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, + ) + + suite.FatalNoError(err) + suite.Equal(1, moveCount) + suite.Len(moves, 1) + }) + + suite.Run("returns moves for USMC GBLOC when moves belong to USMC servicemembers", func() { + officeUser, session := setupTestData("USMC") + + // setting up two moves, each with requested destination SIT service items + // both will be USMC moves, one in Zone II AK and the other not + move, shipment := buildMoveZone2AK(usmc) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + // this one won't be in Zone II + move2, shipment2 := buildMoveZone4AK(usmc) + + // destination shuttle + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( + suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, + ) + + // we should get both moves back since they're USMC moves and zone doesn't matter + suite.FatalNoError(err) + suite.Equal(2, moveCount) + suite.Len(moves, 2) + }) +} From f680a0bba5e4ab9ab082db28c95e0671e062b776 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Wed, 5 Feb 2025 20:28:35 +0000 Subject: [PATCH 11/21] added test for handler --- pkg/handlers/ghcapi/queues_test.go | 141 +++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/pkg/handlers/ghcapi/queues_test.go b/pkg/handlers/ghcapi/queues_test.go index 4711af0de0a..6de9b13dd91 100644 --- a/pkg/handlers/ghcapi/queues_test.go +++ b/pkg/handlers/ghcapi/queues_test.go @@ -1893,3 +1893,144 @@ func (suite *HandlerSuite) TestGetBulkAssignmentDataHandler() { suite.Len(payload.BulkAssignmentMoveIDs, 1) }) } + +func (suite *HandlerSuite) TestGetDestinationRequestsQueuesHandler() { + waf := entitlements.NewWeightAllotmentFetcher() + // default GBLOC is KKFA + officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitActiveOfficeUser(), []roles.RoleType{roles.RoleTypeTOO}) + officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{ + RoleType: roles.RoleTypeTOO, + }) + + postalCode := "90210" + postalCode2 := "73064" + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "90210", "KKFA") + factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), "73064", "JEAT") + + // setting up two moves, one we will see and the other we won't + move := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + destinationAddress := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{PostalCode: postalCode}, + }, + }, nil) + shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: destinationAddress, + LinkOnly: true, + }, + }, nil) + + // destination service item in SUBMITTED status + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDFSIT, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + move2 := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{ + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + Show: models.BoolPointer(true), + }, + }}, nil) + + destinationAddress2 := factory.BuildAddress(suite.DB(), []factory.Customization{ + { + Model: models.Address{PostalCode: postalCode2}, + }, + }, nil) + shipment2 := factory.BuildMTOShipment(suite.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + Status: models.MTOShipmentStatusApproved, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: destinationAddress2, + LinkOnly: true, + }, + }, nil) + + // destination shuttle + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeDDSHUT, + }, + }, + { + Model: move2, + LinkOnly: true, + }, + { + Model: shipment2, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + }, nil) + + request := httptest.NewRequest("GET", "/queues/destination-requests", nil) + request = suite.AuthenticateOfficeRequest(request, officeUser) + params := queues.GetDestinationRequestsQueueParams{ + HTTPRequest: request, + } + handlerConfig := suite.HandlerConfig() + mockUnlocker := movelocker.NewMoveUnlocker() + handler := GetDestinationRequestsQueueHandler{ + handlerConfig, + order.NewOrderFetcher(waf), + mockUnlocker, + officeusercreator.NewOfficeUserFetcherPop(), + } + + response := handler.Handle(params) + suite.IsNotErrResponse(response) + suite.IsType(&queues.GetDestinationRequestsQueueOK{}, response) + payload := response.(*queues.GetDestinationRequestsQueueOK).Payload + + // should only have one move + result := payload.QueueMoves[0] + suite.Len(payload.QueueMoves, 1) + suite.Equal(move.ID.String(), result.ID.String()) +} From ce1423e6dbb3d3be8f22d7b41ce2f460659ee901 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Thu, 6 Feb 2025 16:07:25 +0000 Subject: [PATCH 12/21] added address update to test --- pkg/services/order/order_fetcher_test.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index 653d6d7d129..0e4a26b72bd 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -2536,13 +2536,25 @@ func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() { }, }, nil) + move3, shipment3 := buildMoveKKFA() + factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: move3, + LinkOnly: true, + }, + }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, ) suite.FatalNoError(err) - suite.Equal(2, moveCount) - suite.Len(moves, 2) + suite.Equal(3, moveCount) + suite.Len(moves, 3) }) suite.Run("returns moves for MBFL GBLOC including USAF/SF in Alaska Zone II", func() { From 4fedc408d199b1d37b7751f2c22e739906779911 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Fri, 7 Feb 2025 15:27:22 +0000 Subject: [PATCH 13/21] query improvements, updating csv file name prefix --- ...stination_queue_db_func_and_gbloc_view.up.sql | 16 ++++++++-------- src/pages/Office/MoveQueue/MoveQueue.jsx | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql index 8aabdaeddf0..a17a02d5644 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -351,20 +351,20 @@ BEGIN )::JSONB AS too_assigned, COUNT(*) OVER() AS total_count FROM moves - INNER JOIN orders ON moves.orders_id = orders.id - LEFT JOIN mto_shipments ON mto_shipments.move_id = moves.id + JOIN orders ON moves.orders_id = orders.id + JOIN mto_shipments ON mto_shipments.move_id = moves.id LEFT JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id - LEFT JOIN mto_service_items ON mto_shipments.id = mto_service_items.mto_shipment_id - LEFT JOIN re_services ON mto_service_items.re_service_id = re_services.id - LEFT JOIN service_members ON orders.service_member_id = service_members.id - LEFT JOIN duty_locations AS new_duty_locations ON orders.new_duty_location_id = new_duty_locations.id - LEFT JOIN duty_locations AS origin_duty_locations ON orders.origin_duty_location_id = origin_duty_locations.id + JOIN mto_service_items ON mto_shipments.id = mto_service_items.mto_shipment_id + JOIN re_services ON mto_service_items.re_service_id = re_services.id + JOIN service_members ON orders.service_member_id = service_members.id + JOIN duty_locations AS new_duty_locations ON orders.new_duty_location_id = new_duty_locations.id + JOIN duty_locations AS origin_duty_locations ON orders.origin_duty_location_id = origin_duty_locations.id LEFT JOIN office_users AS too_user ON moves.too_assigned_id = too_user.id LEFT JOIN office_users AS locked_user ON moves.locked_by = locked_user.id LEFT JOIN transportation_offices AS counseling_offices ON moves.counseling_transportation_office_id = counseling_offices.id LEFT JOIN shipment_address_updates ON shipment_address_updates.shipment_id = mto_shipments.id - LEFT JOIN move_to_dest_gbloc ON move_to_dest_gbloc.move_id = moves.id + JOIN move_to_dest_gbloc ON move_to_dest_gbloc.move_id = moves.id WHERE moves.show = TRUE '; diff --git a/src/pages/Office/MoveQueue/MoveQueue.jsx b/src/pages/Office/MoveQueue/MoveQueue.jsx index e0c08868603..36e090a48de 100644 --- a/src/pages/Office/MoveQueue/MoveQueue.jsx +++ b/src/pages/Office/MoveQueue/MoveQueue.jsx @@ -369,9 +369,9 @@ const MoveQueue = ({ isQueueManagementFFEnabled, userPrivileges, isBulkAssignmen handleClick={handleClick} useQueries={useDestinationRequestsQueueQueries} showCSVExport - csvExportFileNamePrefix="Task-Order-Queue" + csvExportFileNamePrefix="Destination-Requests-Queue" csvExportQueueFetcher={getDestinationRequestsQueue} - csvExportQueueFetcherKey="queueMoves" + csvExportQueueFetcherKey="destinationQueueMoves" sessionStorageKey={queueType} key={queueType} /> From f4ce771de883deb5e929e3571a847792ff56938e Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Fri, 7 Feb 2025 16:09:22 +0000 Subject: [PATCH 14/21] test adjustments --- pkg/services/order/order_fetcher_test.go | 60 ++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index 0e4a26b72bd..f597146e48e 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -2537,6 +2537,26 @@ func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() { }, nil) move3, shipment3 := buildMoveKKFA() + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + { + Model: move3, + LinkOnly: true, + }, + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + }, + }, + }, nil) factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ { Model: shipment3, @@ -2713,13 +2733,47 @@ func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() { }, }, nil) + move3, shipment3 := buildMoveZone4AK(usmc) + // we need to create a service item and attach it to the move/shipment + // else the query will exclude the move since it doesn't use LEFT JOINs + factory.BuildMTOServiceItem(suite.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + { + Model: move3, + LinkOnly: true, + }, + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + }, + }, + }, nil) + factory.BuildShipmentAddressUpdate(suite.DB(), []factory.Customization{ + { + Model: shipment3, + LinkOnly: true, + }, + { + Model: move3, + LinkOnly: true, + }, + }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, ) - // we should get both moves back since they're USMC moves and zone doesn't matter + // we should get three moves back since they're USMC moves and zone doesn't matter suite.FatalNoError(err) - suite.Equal(2, moveCount) - suite.Len(moves, 2) + suite.Equal(3, moveCount) + suite.Len(moves, 3) }) } From e38c8634c05337d31689262df4687df01a173859 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Fri, 7 Feb 2025 18:09:16 +0000 Subject: [PATCH 15/21] updating to include moves.show in return --- ...3173216_add_destination_queue_db_func_and_gbloc_view.up.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql index a17a02d5644..5148f0f57d7 100644 --- a/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql +++ b/migrations/app/schema/20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql @@ -266,6 +266,7 @@ CREATE OR REPLACE FUNCTION get_destination_queue( ) RETURNS TABLE ( id UUID, + show BOOLEAN, locator TEXT, submitted_at TIMESTAMP WITH TIME ZONE, orders_id UUID, @@ -299,6 +300,7 @@ BEGIN sql_query := ' SELECT moves.id AS id, + moves.show AS show, moves.locator::TEXT AS locator, moves.submitted_at::TIMESTAMP WITH TIME ZONE AS submitted_at, moves.orders_id AS orders_id, @@ -467,6 +469,7 @@ BEGIN sql_query := sql_query || ' GROUP BY moves.id, + moves.show, moves.locator, moves.submitted_at, moves.orders_id, From c7b7cf1ba4995f2f559c5cf563f6d889b1fe1149 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Mon, 10 Feb 2025 19:27:06 +0000 Subject: [PATCH 16/21] one big ole fat commit, migration added, testharnesses added --- migrations/app/migrations_manifest.txt | 1 + ...st_queue_to_consider_sit_extensions.up.sql | 256 +++ pkg/factory/mto_service_item_factory.go | 484 +++-- pkg/factory/mto_service_item_factory_test.go | 62 + pkg/models/re_service.go | 4 + pkg/services/order/order_fetcher_test.go | 27 +- pkg/testdatagen/testharness/dispatch.go | 264 +++ pkg/testdatagen/testharness/make_move.go | 1606 +++++++++++++++++ playwright/tests/utils/testharness.js | 228 +++ 9 files changed, 2796 insertions(+), 136 deletions(-) create mode 100644 migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index 4973f5559e3..3abe0be5ab9 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -1086,3 +1086,4 @@ 20250120144247_update_pricing_proc_to_use_110_percent_weight.up.sql 20250121153007_update_pricing_proc_to_handle_international_shuttle.up.sql 20250123173216_add_destination_queue_db_func_and_gbloc_view.up.sql +20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql diff --git a/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql b/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql new file mode 100644 index 00000000000..bcfc96ada46 --- /dev/null +++ b/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql @@ -0,0 +1,256 @@ +-- updating to consider sit extensions in PENDING status +CREATE OR REPLACE FUNCTION get_destination_queue( + user_gbloc TEXT DEFAULT NULL, + customer_name TEXT DEFAULT NULL, + edipi TEXT DEFAULT NULL, + emplid TEXT DEFAULT NULL, + m_status TEXT[] DEFAULT NULL, + move_code TEXT DEFAULT NULL, + requested_move_date TIMESTAMP DEFAULT NULL, + date_submitted TIMESTAMP DEFAULT NULL, + branch TEXT DEFAULT NULL, + origin_duty_location TEXT DEFAULT NULL, + counseling_office TEXT DEFAULT NULL, + too_assigned_user TEXT DEFAULT NULL, + page INTEGER DEFAULT 1, + per_page INTEGER DEFAULT 20, + sort TEXT DEFAULT NULL, + sort_direction TEXT DEFAULT NULL +) +RETURNS TABLE ( + id UUID, + show BOOLEAN, + locator TEXT, + submitted_at TIMESTAMP WITH TIME ZONE, + orders_id UUID, + status TEXT, + locked_by UUID, + too_assigned_id UUID, + counseling_transportation_office_id UUID, + orders JSONB, + mto_shipments JSONB, + counseling_transportation_office JSONB, + too_assigned JSONB, + total_count BIGINT +) AS $$ +DECLARE + sql_query TEXT; + offset_value INTEGER; + sort_column TEXT; + sort_order TEXT; +BEGIN + IF page < 1 THEN + page := 1; + END IF; + + IF per_page < 1 THEN + per_page := 20; + END IF; + + offset_value := (page - 1) * per_page; + + sql_query := ' + SELECT + moves.id AS id, + moves.show AS show, + moves.locator::TEXT AS locator, + moves.submitted_at::TIMESTAMP WITH TIME ZONE AS submitted_at, + moves.orders_id AS orders_id, + moves.status::TEXT AS status, + moves.locked_by AS locked_by, + moves.too_assigned_id AS too_assigned_id, + moves.counseling_transportation_office_id AS counseling_transportation_office_id, + json_build_object( + ''id'', orders.id, + ''origin_duty_location_gbloc'', orders.gbloc, + ''service_member'', json_build_object( + ''id'', service_members.id, + ''first_name'', service_members.first_name, + ''last_name'', service_members.last_name, + ''edipi'', service_members.edipi, + ''emplid'', service_members.emplid, + ''affiliation'', service_members.affiliation + ), + ''origin_duty_location'', json_build_object( + ''name'', origin_duty_locations.name + ) + )::JSONB AS orders, + COALESCE( + ( + SELECT json_agg( + json_build_object( + ''id'', ms.id, + ''shipment_type'', ms.shipment_type, + ''status'', ms.status, + ''requested_pickup_date'', TO_CHAR(ms.requested_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''scheduled_pickup_date'', TO_CHAR(ms.scheduled_pickup_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''approved_date'', TO_CHAR(ms.approved_date, ''YYYY-MM-DD"T00:00:00Z"''), + ''prime_estimated_weight'', ms.prime_estimated_weight + ) + ) + FROM ( + SELECT DISTINCT ON (mto_shipments.id) mto_shipments.* + FROM mto_shipments + WHERE mto_shipments.move_id = moves.id + ) AS ms + ), + ''[]'' + )::JSONB AS mto_shipments, + json_build_object( + ''name'', counseling_offices.name + )::JSONB AS counseling_transportation_office, + json_build_object( + ''first_name'', too_user.first_name, + ''last_name'', too_user.last_name + )::JSONB AS too_assigned, + COUNT(*) OVER() AS total_count + FROM moves + JOIN orders ON moves.orders_id = orders.id + JOIN mto_shipments ON mto_shipments.move_id = moves.id + LEFT JOIN ppm_shipments ON ppm_shipments.shipment_id = mto_shipments.id + JOIN mto_service_items ON mto_shipments.id = mto_service_items.mto_shipment_id + JOIN re_services ON mto_service_items.re_service_id = re_services.id + JOIN service_members ON orders.service_member_id = service_members.id + JOIN duty_locations AS new_duty_locations ON orders.new_duty_location_id = new_duty_locations.id + JOIN duty_locations AS origin_duty_locations ON orders.origin_duty_location_id = origin_duty_locations.id + LEFT JOIN office_users AS too_user ON moves.too_assigned_id = too_user.id + LEFT JOIN office_users AS locked_user ON moves.locked_by = locked_user.id + LEFT JOIN transportation_offices AS counseling_offices + ON moves.counseling_transportation_office_id = counseling_offices.id + LEFT JOIN shipment_address_updates ON shipment_address_updates.shipment_id = mto_shipments.id + LEFT JOIN sit_extensions ON sit_extensions.mto_shipment_id = mto_shipments.id + JOIN move_to_dest_gbloc ON move_to_dest_gbloc.move_id = moves.id + WHERE moves.show = TRUE + '; + + IF user_gbloc IS NOT NULL THEN + sql_query := sql_query || ' AND move_to_dest_gbloc.gbloc = $1 '; + END IF; + + IF customer_name IS NOT NULL THEN + sql_query := sql_query || ' AND ( + service_members.first_name || '' '' || service_members.last_name ILIKE ''%'' || $2 || ''%'' + OR service_members.last_name || '' '' || service_members.first_name ILIKE ''%'' || $2 || ''%'' + )'; + END IF; + + IF edipi IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.edipi ILIKE ''%'' || $3 || ''%'' '; + END IF; + + IF emplid IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.emplid ILIKE ''%'' || $4 || ''%'' '; + END IF; + + IF m_status IS NOT NULL THEN + sql_query := sql_query || ' AND moves.status = ANY($5) '; + END IF; + + IF move_code IS NOT NULL THEN + sql_query := sql_query || ' AND moves.locator ILIKE ''%'' || $6 || ''%'' '; + END IF; + + IF requested_move_date IS NOT NULL THEN + sql_query := sql_query || ' AND ( + mto_shipments.requested_pickup_date::DATE = $7::DATE + OR ppm_shipments.expected_departure_date::DATE = $7::DATE + OR (mto_shipments.shipment_type = ''HHG_OUTOF_NTS'' AND mto_shipments.requested_delivery_date::DATE = $7::DATE) + )'; + END IF; + + IF date_submitted IS NOT NULL THEN + sql_query := sql_query || ' AND moves.submitted_at::DATE = $8::DATE '; + END IF; + + IF branch IS NOT NULL THEN + sql_query := sql_query || ' AND service_members.affiliation ILIKE ''%'' || $9 || ''%'' '; + END IF; + + IF origin_duty_location IS NOT NULL THEN + sql_query := sql_query || ' AND origin_duty_locations.name ILIKE ''%'' || $10 || ''%'' '; + END IF; + + IF counseling_office IS NOT NULL THEN + sql_query := sql_query || ' AND counseling_offices.name ILIKE ''%'' || $11 || ''%'' '; + END IF; + + IF too_assigned_user IS NOT NULL THEN + sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%'' || $12 || ''%'' '; + END IF; + + -- add destination queue-specific filters (pending dest address requests, pending dest SIT extension requests, dest SIT & dest shuttle service items) + sql_query := sql_query || ' + AND ( + shipment_address_updates.status = ''REQUESTED'' + OR sit_extensions.status = ''PENDING'' + OR ( + mto_service_items.status = ''SUBMITTED'' + AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSFSC'', ''DDSHUT'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSFSC'', ''IDSHUT'') + ) + ) + '; + + -- default sorting values if none are provided (move.id) + sort_column := 'id'; + sort_order := 'ASC'; + + IF sort IS NOT NULL THEN + CASE sort + WHEN 'locator' THEN sort_column := 'moves.locator'; + WHEN 'status' THEN sort_column := 'moves.status'; + WHEN 'customerName' THEN sort_column := 'service_members.last_name'; + WHEN 'edipi' THEN sort_column := 'service_members.edipi'; + WHEN 'emplid' THEN sort_column := 'service_members.emplid'; + WHEN 'requestedMoveDate' THEN sort_column := 'COALESCE(mto_shipments.requested_pickup_date, ppm_shipments.expected_departure_date, mto_shipments.requested_delivery_date)'; + WHEN 'appearedInTooAt' THEN sort_column := 'COALESCE(moves.submitted_at, moves.approvals_requested_at)'; + WHEN 'branch' THEN sort_column := 'service_members.affiliation'; + WHEN 'originDutyLocation' THEN sort_column := 'origin_duty_locations.name'; + WHEN 'counselingOffice' THEN sort_column := 'counseling_offices.name'; + WHEN 'assignedTo' THEN sort_column := 'too_user.last_name'; + ELSE + sort_column := 'moves.id'; + END CASE; + END IF; + + IF sort_direction IS NOT NULL THEN + IF LOWER(sort_direction) = 'desc' THEN + sort_order := 'DESC'; + ELSE + sort_order := 'ASC'; + END IF; + END IF; + + sql_query := sql_query || ' + GROUP BY + moves.id, + moves.show, + moves.locator, + moves.submitted_at, + moves.orders_id, + moves.status, + moves.locked_by, + moves.too_assigned_id, + moves.counseling_transportation_office_id, + mto_shipments.requested_pickup_date, + mto_shipments.requested_delivery_date, + ppm_shipments.expected_departure_date, + orders.id, + service_members.id, + service_members.first_name, + service_members.last_name, + service_members.edipi, + service_members.emplid, + service_members.affiliation, + origin_duty_locations.name, + counseling_offices.name, + too_user.first_name, + too_user.last_name'; + sql_query := sql_query || format(' ORDER BY %s %s ', sort_column, sort_order); + sql_query := sql_query || ' LIMIT $13 OFFSET $14 '; + + RETURN QUERY EXECUTE sql_query + USING user_gbloc, customer_name, edipi, emplid, m_status, move_code, requested_move_date, date_submitted, + branch, origin_duty_location, counseling_office, too_assigned_user, per_page, offset_value; + +END; +$$ LANGUAGE plpgsql; diff --git a/pkg/factory/mto_service_item_factory.go b/pkg/factory/mto_service_item_factory.go index 2bc9c236f4d..623b3a2c583 100644 --- a/pkg/factory/mto_service_item_factory.go +++ b/pkg/factory/mto_service_item_factory.go @@ -747,7 +747,7 @@ func BuildFullOriginMTOServiceItems(db *pop.Connection, customs []Customization, // are required params, and entryDate and departureDate can be specificed // optionally. func BuildOriginSITServiceItems(db *pop.Connection, move models.Move, shipment models.MTOShipment, entryDate *time.Time, departureDate *time.Time) models.MTOServiceItems { - postalCode := "90210" + postalCode := shipment.PickupAddress.PostalCode reason := "peak season all trucks in use" defaultEntryDate := time.Now().AddDate(0, 0, -45) defaultApprovedAtDate := time.Now() @@ -759,87 +759,193 @@ func BuildOriginSITServiceItems(db *pop.Connection, move models.Move, shipment m defaultDepartureDate = departureDate } - dofsit := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOFSIT, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITPostalCode: &postalCode, - Reason: &reason, + var firstDaySit, addlDaySit, pickupSit, fuelSurchargeSit models.MTOServiceItem + + if shipment.MarketCode != models.MarketCodeInternational { + firstDaySit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOFSIT, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGActualAddress, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGOriginalAddress, - }, - }, nil) + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGActualAddress, + }, + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGOriginalAddress, + }, + }, nil) - doasit := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOASIT, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITPostalCode: &postalCode, - Reason: &reason, + addlDaySit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOASIT, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGActualAddress, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGOriginalAddress, - }, - }, nil) + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGActualAddress, + }, + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGOriginalAddress, + }, + }, nil) - dopsit := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOPSIT, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITDepartureDate: defaultDepartureDate, - SITPostalCode: &postalCode, - Reason: &reason, + pickupSit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOPSIT, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITDepartureDate: defaultDepartureDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGActualAddress, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGOriginalAddress, - }, - }, nil) + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGActualAddress, + }, + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGOriginalAddress, + }, + }, nil) - dosfsc := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOSFSC, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITPostalCode: &postalCode, - Reason: &reason, + fuelSurchargeSit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDOSFSC, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGActualAddress, - }, - { - Model: models.Address{}, - Type: &Addresses.SITOriginHHGOriginalAddress, - }, - }, nil) - return []models.MTOServiceItem{dofsit, doasit, dopsit, dosfsc} + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGActualAddress, + }, + { + Model: models.Address{}, + Type: &Addresses.SITOriginHHGOriginalAddress, + }, + }, nil) + } else { + firstDaySit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIOFSIT, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + addlDaySit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIOASIT, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + pickupSit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIOPSIT, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITDepartureDate: defaultDepartureDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + fuelSurchargeSit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIOSFSC, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + } + + return []models.MTOServiceItem{firstDaySit, addlDaySit, pickupSit, fuelSurchargeSit} } // BuildDestSITServiceItems makes all of the service items that are @@ -847,7 +953,7 @@ func BuildOriginSITServiceItems(db *pop.Connection, move models.Move, shipment m // are required params, and entryDate and departureDate can be specificed // optionally. func BuildDestSITServiceItems(db *pop.Connection, move models.Move, shipment models.MTOShipment, entryDate *time.Time, departureDate *time.Time) models.MTOServiceItems { - postalCode := "90210" + postalCode := shipment.DestinationAddress.PostalCode reason := "peak season all trucks in use" defaultEntryDate := time.Now().AddDate(0, 0, -45) defaultApprovedAtDate := time.Now() @@ -859,71 +965,181 @@ func BuildDestSITServiceItems(db *pop.Connection, move models.Move, shipment mod defaultDepartureDate = departureDate } - ddfsit := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDFSIT, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITPostalCode: &postalCode, - Reason: &reason, + var firstDaySit models.MTOServiceItem + var addlDaySit models.MTOServiceItem + var deliverySit models.MTOServiceItem + var fuelSurchargeSit models.MTOServiceItem + + // handling domestic SIT service item creation vs international + if shipment.MarketCode != models.MarketCodeInternational { + firstDaySit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDFSIT, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - }, nil) + }, nil) - ddasit := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDASIT, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITPostalCode: &postalCode, - Reason: &reason, + addlDaySit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDASIT, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - }, nil) + }, nil) - dddsit := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDDSIT, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITDepartureDate: defaultDepartureDate, - SITPostalCode: &postalCode, - Reason: &reason, + deliverySit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDDSIT, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITDepartureDate: defaultDepartureDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - { - Model: models.Address{}, - Type: &Addresses.SITDestinationFinalAddress, - }, - { - Model: models.Address{}, - Type: &Addresses.SITDestinationOriginalAddress, - }, - }, nil) + { + Model: models.Address{}, + Type: &Addresses.SITDestinationFinalAddress, + }, + { + Model: models.Address{}, + Type: &Addresses.SITDestinationOriginalAddress, + }, + }, nil) - ddsfsc := BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDSFSC, move, shipment, []Customization{ - { - Model: models.MTOServiceItem{ - Status: models.MTOServiceItemStatusApproved, - ApprovedAt: &defaultApprovedAtDate, - SITEntryDate: &defaultEntryDate, - SITPostalCode: &postalCode, - Reason: &reason, + fuelSurchargeSit = BuildRealMTOServiceItemWithAllDeps(db, models.ReServiceCodeDDSFSC, move, shipment, []Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, }, - }, - { - Model: models.Address{}, - Type: &Addresses.SITDestinationFinalAddress, - }, - { - Model: models.Address{}, - Type: &Addresses.SITDestinationOriginalAddress, - }, - }, nil) - return []models.MTOServiceItem{ddfsit, ddasit, dddsit, ddsfsc} + { + Model: models.Address{}, + Type: &Addresses.SITDestinationFinalAddress, + }, + { + Model: models.Address{}, + Type: &Addresses.SITDestinationOriginalAddress, + }, + }, nil) + } else { + firstDaySit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIDFSIT, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + addlDaySit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIDASIT, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + deliverySit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIDDSIT, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITDepartureDate: defaultDepartureDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + fuelSurchargeSit = BuildMTOServiceItem(db, []Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIDSFSC, + }, + }, + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + ApprovedAt: &defaultApprovedAtDate, + SITEntryDate: &defaultEntryDate, + SITPostalCode: &postalCode, + Reason: &reason, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + } + + return []models.MTOServiceItem{firstDaySit, addlDaySit, deliverySit, fuelSurchargeSit} } func BuildDestSITServiceItemsNoSITDepartureDate(db *pop.Connection, move models.Move, shipment models.MTOShipment, entryDate *time.Time) models.MTOServiceItems { diff --git a/pkg/factory/mto_service_item_factory_test.go b/pkg/factory/mto_service_item_factory_test.go index 6287381e981..fe98c4ddba0 100644 --- a/pkg/factory/mto_service_item_factory_test.go +++ b/pkg/factory/mto_service_item_factory_test.go @@ -346,6 +346,68 @@ func (suite *FactorySuite) TestBuildMTOServiceItem() { suite.Equal(expectedCodes, reServiceCodes) }) + suite.Run("Build SIT service items for international shipment - origin SIT", func() { + + customMove := BuildMove(suite.DB(), nil, nil) + customMTOShipment := BuildMTOShipment(suite.DB(), []Customization{ + { + Model: customMove, + LinkOnly: true, + }, + { + Model: models.MTOShipment{ + MarketCode: models.MarketCodeInternational, + }, + }, + }, nil) + + oneMonthLater := time.Now().AddDate(0, 1, 0) + sitServiceItems := BuildOriginSITServiceItems(suite.DB(), customMove, customMTOShipment, &oneMonthLater, nil) + reServiceCodes := []models.ReServiceCode{} + + for i := range sitServiceItems { + reServiceCodes = append(reServiceCodes, sitServiceItems[i].ReService.Code) + } + expectedCodes := []models.ReServiceCode{ + models.ReServiceCodeIOFSIT, + models.ReServiceCodeIOASIT, + models.ReServiceCodeIOPSIT, + models.ReServiceCodeIOSFSC, + } + suite.Equal(expectedCodes, reServiceCodes) + }) + + suite.Run("Build SIT service items for international shipment - destination SIT", func() { + + customMove := BuildMove(suite.DB(), nil, nil) + customMTOShipment := BuildMTOShipment(suite.DB(), []Customization{ + { + Model: customMove, + LinkOnly: true, + }, + { + Model: models.MTOShipment{ + MarketCode: models.MarketCodeInternational, + }, + }, + }, nil) + + oneMonthLater := time.Now().AddDate(0, 1, 0) + sitServiceItems := BuildDestSITServiceItems(suite.DB(), customMove, customMTOShipment, &oneMonthLater, nil) + reServiceCodes := []models.ReServiceCode{} + + for i := range sitServiceItems { + reServiceCodes = append(reServiceCodes, sitServiceItems[i].ReService.Code) + } + expectedCodes := []models.ReServiceCode{ + models.ReServiceCodeIDFSIT, + models.ReServiceCodeIDASIT, + models.ReServiceCodeIDDSIT, + models.ReServiceCodeIDSFSC, + } + suite.Equal(expectedCodes, reServiceCodes) + }) + suite.Run("Port Locations not populated by default", func() { serviceItem := BuildMTOServiceItem(suite.DB(), nil, nil) diff --git a/pkg/models/re_service.go b/pkg/models/re_service.go index 85136a4705a..70f78ccea2b 100644 --- a/pkg/models/re_service.go +++ b/pkg/models/re_service.go @@ -86,6 +86,8 @@ const ( ReServiceCodeIDDSIT ReServiceCode = "IDDSIT" // ReServiceCodeIDFSIT International destination 1st day SIT ReServiceCodeIDFSIT ReServiceCode = "IDFSIT" + // ReServiceCodeIDSFSC International destination SIT FSC + ReServiceCodeIDSFSC ReServiceCode = "IDSFSC" // ReServiceCodeIDSHUT International destination shuttle service ReServiceCodeIDSHUT ReServiceCode = "IDSHUT" // ReServiceCodeIHPK International HHG pack @@ -108,6 +110,8 @@ const ( ReServiceCodeIOOUB ReServiceCode = "IOOUB" // ReServiceCodeIOPSIT International origin SIT pickup ReServiceCodeIOPSIT ReServiceCode = "IOPSIT" + // ReServiceCodeIOSFSC International origin SIT FSC + ReServiceCodeIOSFSC ReServiceCode = "IOSFSC" // ReServiceCodeIOSHUT International origin shuttle service ReServiceCodeIOSHUT ReServiceCode = "IOSHUT" // ReServiceCodeIUBPK International UB pack diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go index f597146e48e..8e0e6eec9e3 100644 --- a/pkg/services/order/order_fetcher_test.go +++ b/pkg/services/order/order_fetcher_test.go @@ -2568,13 +2568,36 @@ func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() { }, }, []factory.Trait{factory.GetTraitShipmentAddressUpdateRequested}) + move4, shipment4 := buildMoveKKFA() + // build the destination SIT service items and update their status to SUBMITTED + oneMonthLater := time.Now().AddDate(0, 1, 0) + factory.BuildDestSITServiceItems(suite.DB(), move4, shipment4, &oneMonthLater, nil) + + // build the SIT extension update + factory.BuildSITDurationUpdate(suite.DB(), []factory.Customization{ + { + Model: move4, + LinkOnly: true, + }, + { + Model: shipment4, + LinkOnly: true, + }, + { + Model: models.SITDurationUpdate{ + Status: models.SITExtensionStatusPending, + ContractorRemarks: models.StringPointer("gimme some more plz"), + }, + }, + }, nil) + moves, moveCount, err := orderFetcher.ListDestinationRequestsOrders( suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{}, ) suite.FatalNoError(err) - suite.Equal(3, moveCount) - suite.Len(moves, 3) + suite.Equal(4, moveCount) + suite.Len(moves, 4) }) suite.Run("returns moves for MBFL GBLOC including USAF/SF in Alaska Zone II", func() { diff --git a/pkg/testdatagen/testharness/dispatch.go b/pkg/testdatagen/testharness/dispatch.go index 0ed11caf74a..4c18f2a95f1 100644 --- a/pkg/testdatagen/testharness/dispatch.go +++ b/pkg/testdatagen/testharness/dispatch.go @@ -272,6 +272,270 @@ var actionDispatcher = map[string]actionFunc{ "InternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO": func(appCtx appcontext.AppContext) testHarnessResponse { return MakeBasicInternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO(appCtx) }, + // basic iHHG move with CONUS -> AK needing TOO approval + "IntlHHGMoveDestAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone1Army(appCtx) + }, + "IntlHHGMoveDestAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone2Army(appCtx) + }, + "IntlHHGMoveDestAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone1AirForce(appCtx) + }, + "IntlHHGMoveDestAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone2AirForce(appCtx) + }, + "IntlHHGMoveDestAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveDestAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveDestAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone1USMC(appCtx) + }, + "IntlHHGMoveDestAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAKZone2USMC(appCtx) + }, + // basic iHHG move with AK -> CONUS needing TOO approval + "IntlHHGMovePickupAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone1Army(appCtx) + }, + "IntlHHGMovePickupAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone2Army(appCtx) + }, + "IntlHHGMovePickupAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone1AirForce(appCtx) + }, + "IntlHHGMovePickupAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone2AirForce(appCtx) + }, + "IntlHHGMovePickupAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone1SpaceForce(appCtx) + }, + "IntlHHGMovePickupAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone2SpaceForce(appCtx) + }, + "IntlHHGMovePickupAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone1USMC(appCtx) + }, + "IntlHHGMovePickupAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMovePickupAKZone2USMC(appCtx) + }, + // iHHG with international origin SIT in SUBMITTED status + "IntlHHGMoveOriginSITRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveOriginSITRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITRequestedAKZone2USMC(appCtx) + }, + // iHHG with international destination SIT in SUBMITTED status + "IntlHHGMoveDestSITRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveDestSITRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITRequestedAKZone2USMC(appCtx) + }, + // iHHG with BOTH international origin & destination SIT in SUBMITTED status + "IntlHHGMoveBothSITRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveBothSITRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothSITRequestedAKZone2USMC(appCtx) + }, + // iHHG with international origin shuttle in SUBMITTED status + "IntlHHGMoveOriginShuttleRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveOriginShuttleRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginShuttleRequestedAKZone2USMC(appCtx) + }, + // iHHG with international destination shuttle in SUBMITTED status + "IntlHHGMoveDestShuttleRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveDestShuttleRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestShuttleRequestedAKZone2USMC(appCtx) + }, + // iHHG with BOTH international origin & destination shuttle in SUBMITTED status + "IntlHHGMoveBothShuttleRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveBothShuttleRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveBothShuttleRequestedAKZone2USMC(appCtx) + }, + // iHHG with a destination address request in REQUESTED status + "IntlHHGMoveDestAddressRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveDestAddressRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestAddressRequestedAKZone2USMC(appCtx) + }, + // iHHG with a PENDING SIT extension request + "IntlHHGMoveSITExtensionRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveSITExtensionRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveSITExtensionRequestedAKZone2USMC(appCtx) + }, + // iHHG with a PENDING excess weight notification + "IntlHHGMoveExcessWeightAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveExcessWeightAKZone1Army(appCtx) + }, + "IntlHHGMoveExcessWeightAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveExcessWeightAKZone2Army(appCtx) + }, + // iUB with a PENDING excess UB weight notification + "IntlUBMoveExcessWeightAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlUBMoveExcessWeightAKZone1Army(appCtx) + }, + "IntlUBMoveExcessWeightAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlUBMoveExcessWeightAKZone2Army(appCtx) + }, } func Actions() []string { diff --git a/pkg/testdatagen/testharness/make_move.go b/pkg/testdatagen/testharness/make_move.go index 3e2f5fed100..cc314d4fca6 100644 --- a/pkg/testdatagen/testharness/make_move.go +++ b/pkg/testdatagen/testharness/make_move.go @@ -9380,3 +9380,1609 @@ func MakeBasicInternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO(appCt return *newmove } + +// makeIntlHHGMoveAKToCONUSSubmitted creates an international HHG move +// with the given affiliation and destination address +// basic iHHG move that will require TOO approval +func makeIntlHHGMoveCONUSToAKSubmitted( + appCtx appcontext.AppContext, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + Status: models.MoveStatusServiceCounselingCompleted, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusSubmitted, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// contains an HHG shipment in SUBMITTED status that requires TOO approval +func MakeIntlHHGMoveDestAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKSubmitted(appCtx, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlHHGMoveAKToCONUSSubmitted creates an international HHG move +// with the given affiliation and pickup address +// basic iHHG move that will require TOO approval +func makeIntlHHGMoveAKToCONUSSubmitted( + appCtx appcontext.AppContext, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + Status: models.MoveStatusServiceCounselingCompleted, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the pickup address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusSubmitted, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + PickupAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + return move +} + +// these create an iHHG move with selected affiliation, pickup of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// contains an HHG shipment in SUBMITTED status that requires TOO approval +func MakeIntlHHGMovePickupAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMovePickupAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMovePickupAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMovePickupAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMovePickupAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMovePickupAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMovePickupAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMovePickupAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlHHGMoveDestSITRequested creates an international HHG move +// with the given affiliation and destination address +// parameters determine if ONLY origin or ONLY dest SIT service items are created +// or BOTH origin & dest are created +func makeIntlHHGMoveWithSITRequested( + appCtx appcontext.AppContext, + isOrigin bool, + isBoth bool, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + estimatedWeight := unit.Pound(2000) + actualWeight := unit.Pound(2000) + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + PrimeEstimatedWeight: &estimatedWeight, + PrimeActualWeight: &actualWeight, + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusApproved, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + // build the origin/destination SIT service items and update their status to SUBMITTED + oneMonthLater := now.AddDate(0, 1, 0) + var sitItems models.MTOServiceItems + if isBoth { + sitItems = factory.BuildOriginSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + destSitItems := factory.BuildDestSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + sitItems = append(sitItems, destSitItems...) + } else if isOrigin { + sitItems = factory.BuildOriginSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + } else { + sitItems = factory.BuildDestSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + } + for i := range sitItems { + sitItems[i].Status = models.MTOServiceItemStatusSubmitted + if err := appCtx.DB().Update(&sitItems[i]); err != nil { + log.Panic(fmt.Errorf("failed to update sit service item: %w", err)) + } + } + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing all 4 international origin SIT service items in SUBMITTED status +func MakeIntlHHGMoveOriginSITRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing all 4 international destination SIT service items in SUBMITTED status +func MakeIntlHHGMoveDestSITRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestSITRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing all 4 international destination SIT service items AND all 4 origin SIT service items in SUBMITTED status +func MakeIntlHHGMoveBothSITRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothSITRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlHHGMoveDestShuttleRequested creates an international HHG move +// with the given affiliation and destination address +// contains either origin, destination, or BOTH origin/destination shuttle in SUBMITTED status +func makeIntlHHGMoveShuttleRequested( + appCtx appcontext.AppContext, + isOrigin bool, + isBoth bool, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + estimatedWeight := unit.Pound(2000) + actualWeight := unit.Pound(2000) + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + PrimeEstimatedWeight: &estimatedWeight, + PrimeActualWeight: &actualWeight, + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusApproved, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + // build the destination shuttle service item in SUBMITTED status + if isBoth { + factory.BuildMTOServiceItem(appCtx.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIOSHUT, + }, + }, + { + Model: models.MTOServiceItem{ + Reason: models.StringPointer("internatioanl destination shuttle"), + EstimatedWeight: models.PoundPointer(1000), + ActualWeight: models.PoundPointer(1000), + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + + factory.BuildMTOServiceItem(appCtx.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIDSHUT, + }, + }, + { + Model: models.MTOServiceItem{ + Reason: models.StringPointer("internatioanl destination shuttle"), + EstimatedWeight: models.PoundPointer(1000), + ActualWeight: models.PoundPointer(1000), + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + } else if isOrigin { + factory.BuildMTOServiceItem(appCtx.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIOSHUT, + }, + }, + { + Model: models.MTOServiceItem{ + Reason: models.StringPointer("internatioanl destination shuttle"), + EstimatedWeight: models.PoundPointer(1000), + ActualWeight: models.PoundPointer(1000), + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + } else { + factory.BuildMTOServiceItem(appCtx.DB(), []factory.Customization{ + { + Model: models.ReService{ + Code: models.ReServiceCodeIDSHUT, + }, + }, + { + Model: models.MTOServiceItem{ + Reason: models.StringPointer("internatioanl destination shuttle"), + EstimatedWeight: models.PoundPointer(1000), + ActualWeight: models.PoundPointer(1000), + Status: models.MTOServiceItemStatusSubmitted, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: shipment, + LinkOnly: true, + }, + }, nil) + } + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing an international origin shuttle request in SUBMITTED status +func MakeIntlHHGMoveOriginShuttleRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginShuttleRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing an international destination shuttle request in SUBMITTED status +func MakeIntlHHGMoveDestShuttleRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestShuttleRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing BOTH international origin & destination shuttle requests in SUBMITTED status +func MakeIntlHHGMoveBothShuttleRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveBothShuttleRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlHHGMoveDestShuttleRequested creates an international HHG move +// with the given affiliation and destination address +// contains international destination shuttle in SUBMITTED status +func makeIntlHHGMoveDestAddressRequested( + appCtx appcontext.AppContext, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + estimatedWeight := unit.Pound(2000) + actualWeight := unit.Pound(2000) + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + PrimeEstimatedWeight: &estimatedWeight, + PrimeActualWeight: &actualWeight, + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusApproved, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + newDeliveryAddress := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: "Another Cold St.", + City: "Juneau", + State: "AK", + PostalCode: "99811", + }, + }, + }, nil) + + // build the shipment destination address update + factory.BuildShipmentAddressUpdate(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: models.ShipmentAddressUpdate{ + Status: models.ShipmentAddressUpdateStatusRequested, + OriginalAddressID: *shipment.DestinationAddressID, + NewAddressID: newDeliveryAddress.ID, + ContractorRemarks: *models.StringPointer("let's move this to another really cold place"), + }, + }, + }, nil) + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing a destination address request that the TOO will be required to review +func MakeIntlHHGMoveDestAddressRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveDestAddressRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveDestAddressRequested(appCtx, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlHHGMoveSITExtensionRequested creates an international HHG move +// with the given affiliation and destination address +// contains a SIT extension request requiring TOO action +func makeIntlHHGMoveSITExtensionRequested( + appCtx appcontext.AppContext, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + estimatedWeight := unit.Pound(2000) + actualWeight := unit.Pound(2000) + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + PrimeEstimatedWeight: &estimatedWeight, + PrimeActualWeight: &actualWeight, + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusApproved, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + // build the destination SIT service items and update their status to SUBMITTED + oneMonthLater := now.AddDate(0, 1, 0) + factory.BuildDestSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + + // build the SIT extension update + factory.BuildSITDurationUpdate(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.SITDurationUpdate{ + Status: models.SITExtensionStatusPending, + ContractorRemarks: models.StringPointer("gimme some more plz"), + }, + }, + }, nil) + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing a destination address request that the TOO will be required to review +func MakeIntlHHGMoveSITExtensionRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveSITExtensionRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlHHGMoveCONUSToAKWithExcessWeight creates an international HHG move +// with the given affiliation and destination address +// contains one approved shipment and an pending at-risk excess weight +func makeIntlHHGMoveCONUSToAKWithExcessWeight( + appCtx appcontext.AppContext, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildApprovalsRequestedMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + ExcessWeightQualifiedAt: &now, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + PrimeEstimatedWeight: models.PoundPointer(8000), + ShipmentType: models.MTOShipmentTypeHHG, + Status: models.MTOShipmentStatusApproved, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing an excess weight alert that requires action from TOO +func MakeIntlHHGMoveExcessWeightAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKWithExcessWeight(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveExcessWeightAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveCONUSToAKWithExcessWeight(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// makeIntlUBMoveCONUSToAKWithExcessWeight creates an international UB move +// with the given affiliation and destination address +// contains one approved shipment and an pending at-risk excess weight +func makeIntlUBMoveCONUSToAKWithExcessWeight( + appCtx appcontext.AppContext, + affiliation models.ServiceMemberAffiliation, + streetAddress, city, state, postalCode string, +) models.Move { + userUploader := newUserUploader(appCtx) + userInfo := newUserInfo("customer") + + user := factory.BuildUser(appCtx.DB(), []factory.Customization{ + { + Model: models.User{ + OktaEmail: userInfo.email, + Active: true, + }, + }, + }, nil) + + customer := factory.BuildExtendedServiceMember(appCtx.DB(), []factory.Customization{ + { + Model: models.ServiceMember{ + PersonalEmail: &userInfo.email, + FirstName: &userInfo.firstName, + LastName: &userInfo.lastName, + CacValidated: true, + Affiliation: &affiliation, + }, + }, + { + Model: user, + LinkOnly: true, + }, + }, nil) + + dependentsAuthorized := true + sitDaysAllowance := 90 + entitlements := factory.BuildEntitlement(appCtx.DB(), []factory.Customization{ + { + Model: models.Entitlement{ + DependentsAuthorized: &dependentsAuthorized, + StorageInTransit: &sitDaysAllowance, + }, + }, + }, nil) + + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: customer, + LinkOnly: true, + }, + { + Model: entitlements, + LinkOnly: true, + }, + { + Model: models.UserUpload{}, + ExtendedParams: &factory.UserUploadExtendedParams{ + UserUploader: userUploader, + AppContext: appCtx, + }, + }, + }, nil) + + now := time.Now() + move := factory.BuildApprovalsRequestedMove(appCtx.DB(), []factory.Customization{ + { + Model: orders, + LinkOnly: true, + }, + { + Model: models.Move{ + ExcessUnaccompaniedBaggageWeightQualifiedAt: &now, + AvailableToPrimeAt: &now, + }, + }, + }, nil) + + requestedPickupDate := now.AddDate(0, 3, 0) + requestedDeliveryDate := requestedPickupDate.AddDate(0, 1, 0) + + // build the destination address using the passed-in parameters. + address := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: streetAddress, + City: city, + State: state, + PostalCode: postalCode, + IsOconus: models.BoolPointer(true), + }, + }, + }, nil) + + shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOShipment{ + PrimeEstimatedWeight: models.PoundPointer(2000), + ShipmentType: models.MTOShipmentTypeUnaccompaniedBaggage, + Status: models.MTOShipmentStatusApproved, + RequestedPickupDate: &requestedPickupDate, + RequestedDeliveryDate: &requestedDeliveryDate, + SITDaysAllowance: &sitDaysAllowance, + DestinationAddressID: &address.ID, + MarketCode: models.MarketCodeInternational, + }, + }, + { + Model: move, + LinkOnly: true, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipment, + LinkOnly: true, + }, + { + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, + }, + }, + }, nil) + + return move +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing an excess weight alert that requires action from TOO +func MakeIntlUBMoveExcessWeightAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlUBMoveCONUSToAKWithExcessWeight(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlUBMoveExcessWeightAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlUBMoveCONUSToAKWithExcessWeight(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} diff --git a/playwright/tests/utils/testharness.js b/playwright/tests/utils/testharness.js index cc84f4c61f9..857c0fffa9a 100644 --- a/playwright/tests/utils/testharness.js +++ b/playwright/tests/utils/testharness.js @@ -694,5 +694,233 @@ export class TestHarness { async buildOfficeUserWithGSR() { return this.buildDefault('OfficeUserWithGSR'); } + + /** + * Use testharness to build international move with requested origin SIT + * @returns {Promise} + */ + async buildIntlHHGMoveOriginSITRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone1Army'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone2Army'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveOriginSITRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveOriginSITRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with requested destination SIT + * @returns {Promise} + */ + async buildIntlHHGMoveDestSITRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone1Army'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone2Army'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveDestSITRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveDestSITRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with both requested origin & destination SIT + * @returns {Promise} + */ + async buildIntlHHGMoveBothSITRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone1Army'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone2Army'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveBothSITRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with requested destination shuttle service + * @returns {Promise} + */ + async buildIntlHHGMoveDestShuttleRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone1Army'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone2Army'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveDestShuttleRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with requested destination address request + * @returns {Promise} + */ + async buildIntlHHGMoveDestAddressRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone1Army'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone2Army'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveDestAddressRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveDestAddressRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with a pending SIT extension request + * @returns {Promise} + */ + async buildIntlHHGMoveSITExtensionRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1Army'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2Army'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveSITExtensionRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with an at risk of excess weight + * @returns {Promise} + */ + async buildIntlHHGMoveExcessWeightAKZone1Army() { + return this.buildDefault('IntlHHGMoveExcessWeightAKZone1Army'); + } + + async buildIntlHHGMoveExcessWeightAKZone2Army() { + return this.buildDefault('IntlHHGMoveExcessWeightAKZone2Army'); + } } export default TestHarness; From b77b09ea7d25d3d1b217d5d52d7f34b3b1fce07e Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Mon, 10 Feb 2025 19:51:59 +0000 Subject: [PATCH 17/21] adding origin SIT extension --- ...st_queue_to_consider_sit_extensions.up.sql | 28 ++++++- pkg/testdatagen/testharness/dispatch.go | 59 +++++++++---- pkg/testdatagen/testharness/make_move.go | 79 +++++++++++++----- playwright/tests/utils/testharness.js | 82 +++++++++++++++---- .../ShipmentServiceItemsTable.test.jsx | 22 ++--- ...pdateServiceItemPricingAndWeights.test.jsx | 6 +- 6 files changed, 206 insertions(+), 70 deletions(-) diff --git a/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql b/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql index bcfc96ada46..1c3d1ceced6 100644 --- a/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql +++ b/migrations/app/schema/20250210175754_B22451_update_dest_queue_to_consider_sit_extensions.up.sql @@ -178,11 +178,14 @@ BEGIN sql_query := sql_query || ' AND (too_user.first_name || '' '' || too_user.last_name) ILIKE ''%'' || $12 || ''%'' '; END IF; - -- add destination queue-specific filters (pending dest address requests, pending dest SIT extension requests, dest SIT & dest shuttle service items) + -- add destination queue-specific filters (pending dest address requests, pending dest SIT extension requests when there are dest SIT service items, submitted dest SIT & dest shuttle service items) sql_query := sql_query || ' AND ( shipment_address_updates.status = ''REQUESTED'' - OR sit_extensions.status = ''PENDING'' + OR ( + sit_extensions.status = ''PENDING'' + AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSFSC'', ''DDSHUT'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSFSC'', ''IDSHUT'') + ) OR ( mto_service_items.status = ''SUBMITTED'' AND re_services.code IN (''DDFSIT'', ''DDASIT'', ''DDDSIT'', ''DDSFSC'', ''DDSHUT'', ''IDFSIT'', ''IDASIT'', ''IDDSIT'', ''IDSFSC'', ''IDSHUT'') @@ -254,3 +257,24 @@ BEGIN END; $$ LANGUAGE plpgsql; + +-- fixing some capitalization discrepencies for consistency +UPDATE re_services +SET name = 'International POE fuel surcharge' +WHERE name = 'International POE Fuel Surcharge'; + +UPDATE re_services +SET name = 'International POD fuel surcharge' +WHERE name = 'International POD Fuel Surcharge'; + +UPDATE re_services +SET name = 'International destination SIT fuel surcharge' +WHERE name = 'International Destination SIT Fuel Surcharge'; + +UPDATE re_services +SET name = 'International origin SIT fuel surcharge' +WHERE name = 'International Origin SIT Fuel Surcharge'; + +UPDATE re_services +SET name = 'International shipping & linehaul' +WHERE name = 'International Shipping & Linehaul'; \ No newline at end of file diff --git a/pkg/testdatagen/testharness/dispatch.go b/pkg/testdatagen/testharness/dispatch.go index 4c18f2a95f1..d3e1cf5c126 100644 --- a/pkg/testdatagen/testharness/dispatch.go +++ b/pkg/testdatagen/testharness/dispatch.go @@ -497,30 +497,55 @@ var actionDispatcher = map[string]actionFunc{ "IntlHHGMoveDestAddressRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { return MakeIntlHHGMoveDestAddressRequestedAKZone2USMC(appCtx) }, - // iHHG with a PENDING SIT extension request - "IntlHHGMoveSITExtensionRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone1Army(appCtx) + // iHHG with a PENDING SIT extension request containing origin SIT + "IntlHHGMoveOriginSITExtensionRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1Army(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone2Army(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2Army(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone1AirForce(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1AirForce(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone2AirForce(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2AirForce(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone1SpaceForce(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1SpaceForce(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone2SpaceForce(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2SpaceForce(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone1USMC(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1USMC(appCtx) }, - "IntlHHGMoveSITExtensionRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { - return MakeIntlHHGMoveSITExtensionRequestedAKZone2USMC(appCtx) + "IntlHHGMoveOriginSITExtensionRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2USMC(appCtx) + }, + // iHHG with a PENDING SIT extension request containing destination SIT + "IntlHHGMoveDestSITExtensionRequestedAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone1Army(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone2Army": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone2Army(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone1AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone1AirForce(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone2AirForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone2AirForce(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone1SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone1SpaceForce(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone2SpaceForce": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone2SpaceForce(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone1USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone1USMC(appCtx) + }, + "IntlHHGMoveDestSITExtensionRequestedAKZone2USMC": func(appCtx appcontext.AppContext) testHarnessResponse { + return MakeIntlHHGMoveDestSITExtensionRequestedAKZone2USMC(appCtx) }, // iHHG with a PENDING excess weight notification "IntlHHGMoveExcessWeightAKZone1Army": func(appCtx appcontext.AppContext) testHarnessResponse { diff --git a/pkg/testdatagen/testharness/make_move.go b/pkg/testdatagen/testharness/make_move.go index cc314d4fca6..3ff5d39c977 100644 --- a/pkg/testdatagen/testharness/make_move.go +++ b/pkg/testdatagen/testharness/make_move.go @@ -10518,6 +10518,7 @@ func MakeIntlHHGMoveDestAddressRequestedAKZone2USMC(appCtx appcontext.AppContext // contains a SIT extension request requiring TOO action func makeIntlHHGMoveSITExtensionRequested( appCtx appcontext.AppContext, + isOrigin bool, affiliation models.ServiceMemberAffiliation, streetAddress, city, state, postalCode string, ) models.Move { @@ -10646,11 +10647,15 @@ func makeIntlHHGMoveSITExtensionRequested( }, }, nil) - // build the destination SIT service items and update their status to SUBMITTED + // build the origin/destination SIT service items oneMonthLater := now.AddDate(0, 1, 0) - factory.BuildDestSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + if isOrigin { + factory.BuildOriginSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + } else { + factory.BuildDestSITServiceItems(appCtx.DB(), move, shipment, &oneMonthLater, nil) + } - // build the SIT extension update + // build the SIT extension update in PENDING status factory.BuildSITDurationUpdate(appCtx.DB(), []factory.Customization{ { Model: shipment, @@ -10668,37 +10673,71 @@ func makeIntlHHGMoveSITExtensionRequested( } // these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) -// containing a destination address request that the TOO will be required to review -func MakeIntlHHGMoveSITExtensionRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +// containing a SIT extension request for a shipment containing origin SIT only +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +} + +func MakeIntlHHGMoveOriginSITExtensionRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, true, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +} + +// these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) +// containing a SIT extension request for a shipment containing destination SIT only +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } -func MakeIntlHHGMoveSITExtensionRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveSITExtensionRequested(appCtx, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") +func MakeIntlHHGMoveDestSITExtensionRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { + return makeIntlHHGMoveSITExtensionRequested(appCtx, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") } // makeIntlHHGMoveCONUSToAKWithExcessWeight creates an international HHG move diff --git a/playwright/tests/utils/testharness.js b/playwright/tests/utils/testharness.js index 857c0fffa9a..d97182f66f3 100644 --- a/playwright/tests/utils/testharness.js +++ b/playwright/tests/utils/testharness.js @@ -876,39 +876,75 @@ export class TestHarness { } /** - * Use testharness to build international move with a pending SIT extension request + * Use testharness to build international move with a pending SIT extension request with origin SIT * @returns {Promise} */ - async buildIntlHHGMoveSITExtensionRequestedAKZone1Army() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1Army'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone1Army'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone2Army() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2Army'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone2Army'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone1AirForce() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1AirForce'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone1AirForce'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone2AirForce() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2AirForce'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone2AirForce'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone1SpaceForce() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1SpaceForce'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone1SpaceForce'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone2SpaceForce() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2SpaceForce'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone2SpaceForce'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone1USMC() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone1USMC'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone1USMC'); } - async buildIntlHHGMoveSITExtensionRequestedAKZone2USMC() { - return this.buildDefault('IntlHHGMoveSITExtensionRequestedAKZone2USMC'); + async buildIntlHHGMoveOriginSITExtensionRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveOriginSITExtensionRequestedAKZone2USMC'); + } + + /** + * Use testharness to build international move with a pending SIT extension request with destination SIT + * @returns {Promise} + */ + async buildIntlHHGMoveDestSITExtensionRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone1Army'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone2Army'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveDestSITExtensionRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveDestSITExtensionRequestedAKZone2USMC'); } /** @@ -922,5 +958,17 @@ export class TestHarness { async buildIntlHHGMoveExcessWeightAKZone2Army() { return this.buildDefault('IntlHHGMoveExcessWeightAKZone2Army'); } + + /** + * Use testharness to build international move with an at risk of UB excess weight + * @returns {Promise} + */ + async buildIntlUBMoveExcessWeightAKZone1Army() { + return this.buildDefault('IntlUBMoveExcessWeightAKZone1Army'); + } + + async buildIntlUBMoveExcessWeightAKZone2Army() { + return this.buildDefault('IntlUBMoveExcessWeightAKZone2Army'); + } } export default TestHarness; diff --git a/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx b/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx index 592ae52467a..d896ad62a6f 100644 --- a/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx +++ b/src/components/Office/ShipmentServiceItemsTable/ShipmentServiceItemsTable.test.jsx @@ -11,14 +11,14 @@ const reServiceItemResponse = [ isAutoApproved: true, marketCode: 'i', serviceCode: 'POEFSC', - serviceName: 'International POE Fuel Surcharge', + serviceName: 'International POE fuel surcharge', shipmentType: 'UNACCOMPANIED_BAGGAGE', }, { isAutoApproved: true, marketCode: 'i', serviceCode: 'PODFSC', - serviceName: 'International POD Fuel Surcharge', + serviceName: 'International POD fuel surcharge', shipmentType: 'UNACCOMPANIED_BAGGAGE', }, { @@ -46,21 +46,21 @@ const reServiceItemResponse = [ isAutoApproved: true, marketCode: 'i', serviceCode: 'POEFSC', - serviceName: 'International POE Fuel Surcharge', + serviceName: 'International POE fuel surcharge', shipmentType: 'HHG', }, { isAutoApproved: true, marketCode: 'i', serviceCode: 'PODFSC', - serviceName: 'International POD Fuel Surcharge', + serviceName: 'International POD fuel surcharge', shipmentType: 'HHG', }, { isAutoApproved: true, marketCode: 'i', serviceCode: 'ISLH', - serviceName: 'International Shipping & Linehaul', + serviceName: 'International shipping & linehaul', shipmentType: 'HHG', }, { @@ -200,25 +200,25 @@ const reServiceItemResponse = [ { marketCode: 'i', serviceCode: 'IOSFSC', - serviceName: 'International Origin SIT Fuel Surcharge', + serviceName: 'International origin SIT fuel surcharge', shipmentType: 'HHG', }, { marketCode: 'i', serviceCode: 'IDSFSC', - serviceName: 'International Destination SIT Fuel Surcharge', + serviceName: 'International destination SIT fuel surcharge', shipmentType: 'HHG', }, { marketCode: 'i', serviceCode: 'IOSFSC', - serviceName: 'International Origin SIT Fuel Surcharge', + serviceName: 'International origin SIT fuel surcharge', shipmentType: 'UNACCOMPANIED_BAGGAGE', }, { marketCode: 'i', serviceCode: 'IDSFSC', - serviceName: 'International Destination SIT Fuel Surcharge', + serviceName: 'International destination SIT fuel furcharge', shipmentType: 'UNACCOMPANIED_BAGGAGE', }, ]; @@ -371,7 +371,7 @@ describe('Shipment Service Items Table', () => { describe('renders the intl UB shipment type (CONUS -> OCONUS) with service items', () => { it.each([ ['International UB price'], - ['International POE Fuel Surcharge'], + ['International POE fuel surcharge'], ['International UB pack'], ['International UB unpack'], ])('expects %s to be in the document', async (serviceItem) => { @@ -386,7 +386,7 @@ describe('Shipment Service Items Table', () => { describe('renders the intl UB shipment type (OCONUS -> CONUS) with service items', () => { it.each([ ['International UB price'], - ['International POD Fuel Surcharge'], + ['International POD fuel surcharge'], ['International UB pack'], ['International UB unpack'], ])('expects %s to be in the document', async (serviceItem) => { diff --git a/src/constants/MoveHistory/EventTemplates/UpdateMTOServiceItem/updateServiceItemPricingAndWeights.test.jsx b/src/constants/MoveHistory/EventTemplates/UpdateMTOServiceItem/updateServiceItemPricingAndWeights.test.jsx index eae1e8fe630..cfc63966876 100644 --- a/src/constants/MoveHistory/EventTemplates/UpdateMTOServiceItem/updateServiceItemPricingAndWeights.test.jsx +++ b/src/constants/MoveHistory/EventTemplates/UpdateMTOServiceItem/updateServiceItemPricingAndWeights.test.jsx @@ -8,7 +8,7 @@ import t from 'constants/MoveHistory/Database/Tables'; describe('when given an UpdateMTOServiceItem history record with pricing/weight changes', () => { const context = [ { - name: 'International Shipping & Linehaul', + name: 'International shipping & linehaul', shipment_type: 'HHG', shipment_locator: 'RQ38D4-01', shipment_id_abbr: 'a1b2c', @@ -31,7 +31,7 @@ describe('when given an UpdateMTOServiceItem history record with pricing/weight render(template.getDetails(historyRecord)); expect(screen.getByText('Service item')).toBeInTheDocument(); - expect(screen.getByText(/International Shipping & Linehaul/)).toBeInTheDocument(); + expect(screen.getByText(/International shipping & linehaul/)).toBeInTheDocument(); expect(screen.getByText('Estimated Price')).toBeInTheDocument(); expect(screen.getByText(/\$1,500\.00/)).toBeInTheDocument(); }); @@ -52,7 +52,7 @@ describe('when given an UpdateMTOServiceItem history record with pricing/weight render(template.getDetails(historyRecord)); expect(screen.getByText('Service item')).toBeInTheDocument(); - expect(screen.getByText(/International Shipping & Linehaul/)).toBeInTheDocument(); + expect(screen.getByText(/International shipping & linehaul/)).toBeInTheDocument(); expect(screen.getByText('Estimated weight')).toBeInTheDocument(); expect(screen.getByText(/1,000 lbs/)).toBeInTheDocument(); }); From 4c42ca81c20ec5ab3f79aadf54bd15a134c496d7 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 11 Feb 2025 14:56:30 +0000 Subject: [PATCH 18/21] adding origin and both shuttle to testharness - whoops --- playwright/tests/utils/testharness.js | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/playwright/tests/utils/testharness.js b/playwright/tests/utils/testharness.js index d97182f66f3..d9f69540d35 100644 --- a/playwright/tests/utils/testharness.js +++ b/playwright/tests/utils/testharness.js @@ -803,6 +803,42 @@ export class TestHarness { return this.buildDefault('IntlHHGMoveBothSITRequestedAKZone2USMC'); } + /** + * Use testharness to build international move with requested origin shuttle service + * @returns {Promise} + */ + async buildIntlHHGMoveOriginShuttleRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone1Army'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone2Army'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveOriginShuttleRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveOriginShuttleRequestedAKZone2USMC'); + } + /** * Use testharness to build international move with requested destination shuttle service * @returns {Promise} @@ -839,6 +875,42 @@ export class TestHarness { return this.buildDefault('IntlHHGMoveDestShuttleRequestedAKZone2USMC'); } + /** + * Use testharness to build international move with both requested origin & destination shuttle service + * @returns {Promise} + */ + async buildIntlHHGMoveBothShuttleRequestedAKZone1Army() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone1Army'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone2Army() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone2Army'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone1AirForce() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone1AirForce'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone2AirForce() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone2AirForce'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone1SpaceForce() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone1SpaceForce'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone2SpaceForce() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone2SpaceForce'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone1USMC() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone1USMC'); + } + + async buildIntlHHGMoveBothShuttleRequestedAKZone2USMC() { + return this.buildDefault('IntlHHGMoveBothShuttleRequestedAKZone2USMC'); + } + /** * Use testharness to build international move with requested destination address request * @returns {Promise} From d2ab8bf6f7fb50e07b4447344c873b93d27505d7 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Tue, 11 Feb 2025 16:07:24 +0000 Subject: [PATCH 19/21] updating comments --- pkg/testdatagen/testharness/make_move.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/testdatagen/testharness/make_move.go b/pkg/testdatagen/testharness/make_move.go index 3ff5d39c977..ebb8e3fd29b 100644 --- a/pkg/testdatagen/testharness/make_move.go +++ b/pkg/testdatagen/testharness/make_move.go @@ -9381,7 +9381,7 @@ func MakeBasicInternationalHHGMoveWithServiceItemsandPaymentRequestsForTIO(appCt return *newmove } -// makeIntlHHGMoveAKToCONUSSubmitted creates an international HHG move +// makeIntlHHGMoveCONUSToAKSubmitted creates an international HHG move // with the given affiliation and destination address // basic iHHG move that will require TOO approval func makeIntlHHGMoveCONUSToAKSubmitted( @@ -9713,7 +9713,7 @@ func MakeIntlHHGMovePickupAKZone2USMC(appCtx appcontext.AppContext) models.Move return makeIntlHHGMoveAKToCONUSSubmitted(appCtx, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") } -// makeIntlHHGMoveDestSITRequested creates an international HHG move +// makeIntlHHGMoveWithSITRequested creates an international HHG move // with the given affiliation and destination address // parameters determine if ONLY origin or ONLY dest SIT service items are created // or BOTH origin & dest are created @@ -9973,7 +9973,7 @@ func MakeIntlHHGMoveBothSITRequestedAKZone2USMC(appCtx appcontext.AppContext) mo return makeIntlHHGMoveWithSITRequested(appCtx, false, true, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") } -// makeIntlHHGMoveDestShuttleRequested creates an international HHG move +// makeIntlHHGMoveShuttleRequested creates an international HHG move // with the given affiliation and destination address // contains either origin, destination, or BOTH origin/destination shuttle in SUBMITTED status func makeIntlHHGMoveShuttleRequested( @@ -10312,9 +10312,9 @@ func MakeIntlHHGMoveBothShuttleRequestedAKZone2USMC(appCtx appcontext.AppContext return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") } -// makeIntlHHGMoveDestShuttleRequested creates an international HHG move +// makeIntlHHGMoveDestAddressRequested creates an international HHG move // with the given affiliation and destination address -// contains international destination shuttle in SUBMITTED status +// contains a pending destination address request func makeIntlHHGMoveDestAddressRequested( appCtx appcontext.AppContext, affiliation models.ServiceMemberAffiliation, From e1f94ef186f4772a4a6a53b804b6876cd0be92d3 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Wed, 12 Feb 2025 19:28:19 +0000 Subject: [PATCH 20/21] test fixes --- .../ghcapi/internal/payloads/model_to_payload_test.go | 6 +++--- pkg/services/mto_shipment/shipment_approver_test.go | 4 ++-- src/pages/PrimeUI/MoveTaskOrder/MoveDetails.test.jsx | 4 ++-- .../PrimeUIUpdateInternationalFuelSurchargeForm.test.jsx | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) 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 51be3548bc0..9c1c9b3c565 100644 --- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go +++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload_test.go @@ -904,7 +904,7 @@ func (suite *PayloadsSuite) TestReServiceItem() { isAutoApproved := true marketCodeInternational := models.MarketCodeInternational reServiceCode := models.ReServiceCodePOEFSC - poefscServiceName := "International POE Fuel Surcharge" + poefscServiceName := "International POE fuel surcharge" reService := models.ReService{ Code: reServiceCode, Name: poefscServiceName, @@ -936,8 +936,8 @@ func (suite *PayloadsSuite) TestReServiceItems() { marketCodeDomestic := models.MarketCodeDomestic poefscReServiceCode := models.ReServiceCodePOEFSC podfscReServiceCode := models.ReServiceCodePODFSC - poefscServiceName := "International POE Fuel Surcharge" - podfscServiceName := "International POD Fuel Surcharge" + poefscServiceName := "International POE fuel surcharge" + podfscServiceName := "International POD fuel surcharge" poefscService := models.ReService{ Code: poefscReServiceCode, Name: poefscServiceName, diff --git a/pkg/services/mto_shipment/shipment_approver_test.go b/pkg/services/mto_shipment/shipment_approver_test.go index 05910c803af..4695f4383db 100644 --- a/pkg/services/mto_shipment/shipment_approver_test.go +++ b/pkg/services/mto_shipment/shipment_approver_test.go @@ -1132,7 +1132,7 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { } expectedReServiceNames := []string{ "International UB price", - "International POE Fuel Surcharge", + "International POE fuel surcharge", "International UB pack", "International UB unpack", } @@ -1200,7 +1200,7 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() { } expectedReServiceNames := []string{ "International UB price", - "International POD Fuel Surcharge", + "International POD fuel surcharge", "International UB pack", "International UB unpack", } diff --git a/src/pages/PrimeUI/MoveTaskOrder/MoveDetails.test.jsx b/src/pages/PrimeUI/MoveTaskOrder/MoveDetails.test.jsx index a65e16d981d..afa8648da04 100644 --- a/src/pages/PrimeUI/MoveTaskOrder/MoveDetails.test.jsx +++ b/src/pages/PrimeUI/MoveTaskOrder/MoveDetails.test.jsx @@ -178,7 +178,7 @@ const moveTaskOrder = { id: 'serviceItemPOEFSC', moveTaskOrderID: 'aa8dfe13-266a-4956-ac60-01c2355c06d3', mtoShipmentID: '6', - reServiceName: 'International POD Fuel Surcharge', + reServiceName: 'International POD fuel surcharge', status: 'APPROVED', }, { @@ -187,7 +187,7 @@ const moveTaskOrder = { id: 'serviceItemPOEFSC', moveTaskOrderID: 'aa8dfe13-266a-4956-ac60-01c2355c06d3', mtoShipmentID: '5', - reServiceName: 'International POE Fuel Surcharge', + reServiceName: 'International POE fuel surcharge', status: 'APPROVED', }, ], diff --git a/src/pages/PrimeUI/UpdateServiceItems/PrimeUIUpdateInternationalFuelSurchargeForm.test.jsx b/src/pages/PrimeUI/UpdateServiceItems/PrimeUIUpdateInternationalFuelSurchargeForm.test.jsx index 78461a6e840..7a92ae361d2 100644 --- a/src/pages/PrimeUI/UpdateServiceItems/PrimeUIUpdateInternationalFuelSurchargeForm.test.jsx +++ b/src/pages/PrimeUI/UpdateServiceItems/PrimeUIUpdateInternationalFuelSurchargeForm.test.jsx @@ -12,7 +12,7 @@ const mtoServiceItemID = '38569958-2889-41e5-8101-82c56ec48430'; const serviceItem = { id: mtoServiceItemID, reServiceCode: 'POEFSC', - reServiceName: 'International POE Fuel Surcharge', + reServiceName: 'International POE fuel surcharge', status: 'APPROVED', mtoShipmentID: '38569958-2889-41e5-8102-82c56ec48430', }; @@ -64,7 +64,7 @@ describe('PrimeUIUpdateInternationalFuelSurchargeForm', () => { screen.getByRole('heading', { name: 'Update International Fuel Surcharge Service Item', level: 2 }), ).toBeInTheDocument(); expect( - screen.getByRole('heading', { name: 'POEFSC - International POE Fuel Surcharge', level: 3 }), + screen.getByRole('heading', { name: 'POEFSC - International POE fuel surcharge', level: 3 }), ).toBeInTheDocument(); expect(screen.getByText('Port:')).toBeInTheDocument(); expect(screen.getByText('SEATTLE TACOMA INTL')).toBeInTheDocument(); From a837c14033bfb3f7330c93c114b1512503966079 Mon Sep 17 00:00:00 2001 From: Daniel Jordan Date: Thu, 13 Feb 2025 20:59:05 +0000 Subject: [PATCH 21/21] updating testharnesses with forgotten mistakes --- pkg/testdatagen/testharness/make_move.go | 180 +++++++++++++++-------- 1 file changed, 117 insertions(+), 63 deletions(-) diff --git a/pkg/testdatagen/testharness/make_move.go b/pkg/testdatagen/testharness/make_move.go index ebb8e3fd29b..aba9d07a645 100644 --- a/pkg/testdatagen/testharness/make_move.go +++ b/pkg/testdatagen/testharness/make_move.go @@ -10247,69 +10247,69 @@ func MakeIntlHHGMoveOriginShuttleRequestedAKZone2USMC(appCtx appcontext.AppConte // these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) // containing an international destination shuttle request in SUBMITTED status func MakeIntlHHGMoveDestShuttleRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveDestShuttleRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") } func MakeIntlHHGMoveDestShuttleRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveDestShuttleRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") } func MakeIntlHHGMoveDestShuttleRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveDestShuttleRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") } func MakeIntlHHGMoveDestShuttleRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveDestShuttleRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") } // these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) // containing BOTH international origin & destination shuttle requests in SUBMITTED status func MakeIntlHHGMoveBothShuttleRequestedAKZone1Army(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationARMY, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveBothShuttleRequestedAKZone2Army(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationARMY, "Alaska Zone II St.", "North Pole", "AK", "99705") } func MakeIntlHHGMoveBothShuttleRequestedAKZone1AirForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationAIRFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveBothShuttleRequestedAKZone2AirForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationAIRFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") } func MakeIntlHHGMoveBothShuttleRequestedAKZone1SpaceForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationSPACEFORCE, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveBothShuttleRequestedAKZone2SpaceForce(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationSPACEFORCE, "Alaska Zone II St.", "North Pole", "AK", "99705") } func MakeIntlHHGMoveBothShuttleRequestedAKZone1USMC(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationMARINES, "Alaska Zone I Ave.", "Anchorage", "AK", "99505") } func MakeIntlHHGMoveBothShuttleRequestedAKZone2USMC(appCtx appcontext.AppContext) models.Move { - return makeIntlHHGMoveShuttleRequested(appCtx, true, false, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") + return makeIntlHHGMoveShuttleRequested(appCtx, false, true, models.AffiliationMARINES, "Alaska Zone II St.", "North Pole", "AK", "99705") } // makeIntlHHGMoveDestAddressRequested creates an international HHG move @@ -10359,7 +10359,23 @@ func makeIntlHHGMoveDestAddressRequested( }, }, nil) + var departmentIndicator *string = nil + if affiliation == models.AffiliationAIRFORCE || affiliation == models.AffiliationSPACEFORCE { + departmentIndicator = models.StringPointer(models.DepartmentIndicatorAIRANDSPACEFORCE.String()) + } else if affiliation == models.AffiliationNAVY || affiliation == models.AffiliationMARINES { + departmentIndicator = models.StringPointer(models.DepartmentIndicatorNAVYANDMARINES.String()) + } else if affiliation == models.AffiliationARMY { + departmentIndicator = models.StringPointer(models.DepartmentIndicatorARMY.String()) + } else if affiliation == models.AffiliationCOASTGUARD { + departmentIndicator = models.StringPointer(models.DepartmentIndicatorCOASTGUARD.String()) + } + orders := factory.BuildOrder(appCtx.DB(), []factory.Customization{ + { + Model: models.Order{ + DepartmentIndicator: departmentIndicator, + }, + }, { Model: customer, LinkOnly: true, @@ -10378,18 +10394,6 @@ func makeIntlHHGMoveDestAddressRequested( }, nil) now := time.Now() - move := factory.BuildMove(appCtx.DB(), []factory.Customization{ - { - Model: orders, - LinkOnly: true, - }, - { - Model: models.Move{ - Status: models.MoveStatusAPPROVALSREQUESTED, - AvailableToPrimeAt: &now, - }, - }, - }, nil) estimatedWeight := unit.Pound(2000) actualWeight := unit.Pound(2000) @@ -10409,7 +10413,19 @@ func makeIntlHHGMoveDestAddressRequested( }, }, nil) - shipment := factory.BuildMTOShipment(appCtx.DB(), []factory.Customization{ + newDeliveryAddress := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + { + Model: models.Address{ + StreetAddress1: "Another Cold St.", + City: "Juneau", + State: "AK", + PostalCode: "99811", + }, + }, + }, nil) + + // build the shipment destination address update + shipmentAddressUpdate := factory.BuildShipmentAddressUpdate(appCtx.DB(), []factory.Customization{ { Model: models.MTOShipment{ PrimeEstimatedWeight: &estimatedWeight, @@ -10424,59 +10440,61 @@ func makeIntlHHGMoveDestAddressRequested( }, }, { - Model: move, - LinkOnly: true, + Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, + AvailableToPrimeAt: &now, + Show: models.BoolPointer(true), + }, }, - }, nil) - - agentUserInfo := newUserInfo("agent") - factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ { - Model: shipment, - LinkOnly: true, + Model: models.ShipmentAddressUpdate{ + Status: models.ShipmentAddressUpdateStatusRequested, + OriginalAddressID: address.ID, + NewAddressID: newDeliveryAddress.ID, + ContractorRemarks: *models.StringPointer("let's move this to another really cold place"), + }, }, { - Model: models.MTOAgent{ - FirstName: &agentUserInfo.firstName, - LastName: &agentUserInfo.lastName, - Email: &agentUserInfo.email, - MTOAgentType: models.MTOAgentReleasing, - }, + Model: orders, + LinkOnly: true, }, }, nil) - newDeliveryAddress := factory.BuildAddress(appCtx.DB(), []factory.Customization{ + factory.BuildMTOServiceItemBasic(appCtx.DB(), []factory.Customization{ { - Model: models.Address{ - StreetAddress1: "Another Cold St.", - City: "Juneau", - State: "AK", - PostalCode: "99811", + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + MTOShipmentID: &shipmentAddressUpdate.Shipment.ID, }, }, - }, nil) - - // build the shipment destination address update - factory.BuildShipmentAddressUpdate(appCtx.DB(), []factory.Customization{ { - Model: shipment, + Model: shipmentAddressUpdate.Shipment.MoveTaskOrder, LinkOnly: true, }, { - Model: move, + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + }, nil) + + agentUserInfo := newUserInfo("agent") + factory.BuildMTOAgent(appCtx.DB(), []factory.Customization{ + { + Model: shipmentAddressUpdate.Shipment, LinkOnly: true, }, { - Model: models.ShipmentAddressUpdate{ - Status: models.ShipmentAddressUpdateStatusRequested, - OriginalAddressID: *shipment.DestinationAddressID, - NewAddressID: newDeliveryAddress.ID, - ContractorRemarks: *models.StringPointer("let's move this to another really cold place"), + Model: models.MTOAgent{ + FirstName: &agentUserInfo.firstName, + LastName: &agentUserInfo.lastName, + Email: &agentUserInfo.email, + MTOAgentType: models.MTOAgentReleasing, }, }, }, nil) - return move + return shipmentAddressUpdate.Shipment.MoveTaskOrder } // these create an iHHG move with selected affiliation, destination of either Anchorage, AK (Zone I) or Fairbanks, AK (Zone II) @@ -10806,15 +10824,15 @@ func makeIntlHHGMoveCONUSToAKWithExcessWeight( }, nil) now := time.Now() - move := factory.BuildApprovalsRequestedMove(appCtx.DB(), []factory.Customization{ + move := factory.BuildAvailableToPrimeMove(appCtx.DB(), []factory.Customization{ { Model: orders, LinkOnly: true, }, { Model: models.Move{ + Status: models.MoveStatusAPPROVALSREQUESTED, ExcessWeightQualifiedAt: &now, - AvailableToPrimeAt: &now, }, }, }, nil) @@ -10870,6 +10888,24 @@ func makeIntlHHGMoveCONUSToAKWithExcessWeight( }, }, nil) + factory.BuildMTOServiceItemBasic(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + MTOShipmentID: &shipment.ID, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + }, nil) + return move } @@ -11013,6 +11049,24 @@ func makeIntlUBMoveCONUSToAKWithExcessWeight( }, }, nil) + factory.BuildMTOServiceItemBasic(appCtx.DB(), []factory.Customization{ + { + Model: models.MTOServiceItem{ + Status: models.MTOServiceItemStatusApproved, + MTOShipmentID: &shipment.ID, + }, + }, + { + Model: move, + LinkOnly: true, + }, + { + Model: models.ReService{ + Code: models.ReServiceCodeMS, + }, + }, + }, nil) + return move }