diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index da9f9399d77..5909d3e55c9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -30,7 +30,7 @@ variables:
# Specify the environment: loadtest, demo, exp
DP3_ENV: &dp3_env placeholder_env
- # Specify the branch to deploy
+ # Specify the branch to deploy TODO: this might be not needed. So far useless
DP3_BRANCH: &dp3_branch placeholder_branch_name
# Ignore branches for integration tests
@@ -39,6 +39,14 @@ variables:
CLIENT_IGNORE_BRANCH: &client_ignore_branch placeholder_branch_name
SERVER_IGNORE_BRANCH: &server_ignore_branch placeholder_branch_name
+ #RUNNER_TAG: &runner_tag milmove
+ RUNNER_TAG: &runner_tag milmove
+ DOCKER_RUNNER_TAG: &docker_runner_tag eks_cluster_runner
+
+ postgres: &postgres postgres:16.4
+ #postgres: &postgres postgres:16.4
+ redis: &redis redis:5.0.6
+
stages:
- pre_checks
- build
@@ -57,24 +65,42 @@ stages:
- export REACT_APP_ERROR_LOGGING=otel
.announce_failure: &announce_failure
- - if [[ "$CI_COMMIT_BRANCH" == "main" && "$CI_JOB_STATUS" == "failed" ]]; then
- echo "Announcing broken branch in GitLab CI"
+ #- if [[ "$CI_COMMIT_BRANCH" == "main" && "$CI_JOB_STATUS" == "failed" ]]; then
+ - echo $CI_COMMIT_BRANCH
+ - echo $CI_JOB_STATUS
+ - echo "Announcing broken branch in GitLab CI"
+ # fi
+
+.setup_tls_vars_dp3: &setup_tls_vars_dp3
+ - |
+ if [[ "$DP3_ENV" == "exp" || "$DP3_ENV" == "loadtest" || "$DP3_ENV" == "demo" ]]; then
+ export ENV=$(echo ${DP3_ENV} | tr '[:lower:]' '[:upper:]');
+ export TLS_CERT=$(eval echo \$${ENV^^}_DP3_CERT);
+ export TLS_KEY=$(eval echo \$${ENV^^}_DP3_KEY);
+ export TLS_CA=$(eval echo \$${ENV^^}_DP3_CA);
fi
.setup_aws_vars_dp3: &setup_aws_vars_dp3
- - if [[ "$DP3_ENV" == "exp" OR "$DP3_ENV" == "loadtest" OR "$DP3_ENV" == "demo" ]]; then
- export AWS_DEFAULT_REGION=$(eval echo \$${DP3_ENV^^}_REGION)
- export AWS_ACCOUNT_ID=$(eval echo \$${DP3_ENV^^}_ACCOUNT_ID)
- export AWS_ACCESS_KEY_ID=$(eval echo \$${DP3_ENV^^}_ACCESS_KEY_ID)
- export AWS_SECRET_ACCESS_KEY=$(eval echo \$${DP3_ENV^^}_SECRET_ACCESS_KEY)
+ - |
+ if [[ "$DP3_ENV" == "exp" || "$DP3_ENV" == "loadtest" || "$DP3_ENV" == "demo" ]]; then
+ export ENV=$(echo ${DP3_ENV} | tr '[:lower:]' '[:upper:]');
+ export AWS_DEFAULT_REGION=$(eval echo \$${ENV^^}_REGION);
+ export AWS_ACCOUNT_ID=$(eval echo \$${ENV^^}_ACCOUNT_ID);
+ export AWS_ACCESS_KEY_ID=$(eval echo \$${ENV^^}_ACCESS_KEY_ID);
+ export AWS_SECRET_ACCESS_KEY=$(eval echo \$${ENV^^}_SECRET_ACCESS_KEY);
fi
-.setup_tls_vars_dp3: &setup_tls_vars_dp3
- - if [[ "$DP3_ENV" == "exp" OR "$DP3_ENV" == "loadtest" OR "$DP3_ENV" == "demo" ]]; then
- export TLS_CERT=$(eval echo \$${DP3_ENV^^}_DP3_CERT)
- export TLS_KEY=$(eval echo \$${DP3_ENV^^}_DP3_KEY)
- export TLS_CA=$(eval echo \$${DP3_ENV^^}_DP3_CA)
- fi
+.setup_release_dp3: &setup_release_dp3
+ - |
+ if [[ "$DP3_ENV" == "exp" || "$DP3_ENV" == "loadtest" || "$DP3_ENV" == "demo" ]]; then
+ export ENV=$(echo ${DP3_ENV} | tr '[:lower:]' '[:upper:]');
+ export AWS_REGION=$(eval echo \$${ENV}_REGION);
+ export AWS_ACCOUNT_ID=$(eval echo \$${ENV}_ACCOUNT_ID);
+ export ECR_REPOSITORY_URI=$(echo ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com)
+ export APP_DOCKER_FILE=Dockerfile.dp3
+ export TASK_DOCKER_FILE=Dockerfile.tasks_dp3
+ export APP_ENVIRONMENT=$ENV
+ fi
.setup_aws_vars_stg: &setup_aws_vars_stg
- export AWS_DEFAULT_REGION=$STG_REGION
@@ -100,14 +126,6 @@ stages:
- export TLS_KEY=$PRD_MOVE_MIL_DOD_TLS_KEY
- export TLS_CA=$PRD_MOVE_MIL_DOD_TLS_CA
-.setup_release_dp3: &setup_release_dp3
- #if demo/loadtest/exp
- - export ECR_REPOSITORY_URI=$(eval echo \$${DP3_ENV^^}_ACCOUNT_ID).dkr.ecr.$(eval echo \$${DP3_ENV^^}_REGION).amazonaws.com
- - export APP_DOCKER_FILE=Dockerfile.dp3
- - export TASK_DOCKER_FILE=Dockerfile.tasks_dp3
- - export APP_ENVIRONMENT=$DPS_ENV
- - echo ${ECR_REPOSITORY_URI}
-
.setup_release_stg: &setup_release_stg
#if main
- export ECR_REPOSITORY_URI=${STG_ACCOUNT_ID}.dkr.ecr.${STG_REGION}.amazonaws.com
@@ -115,7 +133,6 @@ stages:
- export TASK_DOCKER_FILE=Dockerfile.tasks_dp3
#TODO: update demo to stg
- export APP_ENVIRONMENT=demo
- - echo ${ECR_REPOSITORY_URI}
.setup_release_prd: &setup_release_prd
#build off prd variables
@@ -124,7 +141,6 @@ stages:
- export TASK_DOCKER_FILE=Dockerfile.tasks_dp3
#TODO: update exp to prod
- export APP_ENVIRONMENT=exp
- - echo ${ECR_REPOSITORY_URI}
.kaniko_before_setup: &kaniko_before_setup
# prep login for kaniko
@@ -141,9 +157,93 @@ stages:
.check_debug: &check_debug
- if: '$debug == "true"'
+.check_integration_ignore_branch: &check_integration_ignore_branch
+ - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == $INTEGRATION_IGNORE_BRANCH'
+
+.check_integration_mtls_ignore_branch: &check_integration_mtls_ignore_branch
+ - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == $INTEGRATION_MTLS_IGNORE_BRANCH'
+
+.check_client_ignore_branch: &check_client_ignore_branch
+ - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == $CLIENT_IGNORE_BRANCH'
+
+.check_server_ignore_branch: &check_server_ignore_branch
+ - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == $SERVER_IGNORE_BRANCH'
+
+
+.install_yarn: &install_yarn
+ - |
+ mkdir -p /builds/milmove/mymove/.cache
+ mkdir -p /builds/milmove/mymove/.cache/yarn
+ yarn install --frozen-lockfile --cache-folder /builds/milmove/mymove/.cache/yarn
+ scripts/check-generated-code yarn.lock
+ echo "yarn check dependencies"
+ ./scripts/rebuild-dependencies-without-binaries
+
+.yarn_cache: &yarn_cache
+ key:
+ files:
+ - yarn.lock
+ paths:
+ - .cache/yarn
+
+.go_cache: &go_cache
+ key:
+ files:
+ - go.sum
+ paths:
+ - $GOPATH/pkg/mod
+ - /builds/milmove/mymove/bin
+
+.setup_generic_app_env_variables: &setup_generic_app_env_variables
+ - |
+ export APPLICATION=app
+ export DB_PASSWORD=mysecretpassword
+ export DB_USER_LOW_PRIV=crud
+ export DB_PASSWORD_LOW_PRIV=mysecretpassword
+ export DB_USER=postgres
+ export DB_HOST=localhost
+ export DB_PORT=5432
+ export MIGRATION_MANIFEST='/builds/milmove/mymove/migrations/app/migrations_manifest.txt'
+ export MIGRATION_PATH='file:///builds/milmove/mymove/migrations/app/schema;file:///builds/milmove/mymove/migrations/app/secure'
+ export EIA_KEY=db2522a43820268a41a802a16ae9fd26
+
+.setup_devseed_env_variables: &setup_devseed_env_variables
+ - |
+ export DB_NAME=dev_db
+ export DB_NAME_DEV=dev_db
+ export ENVIRONMENT=development
+ export DOD_CA_PACKAGE=/builds/milmove/mymove/config/tls/milmove-cert-bundle.p7b
+
+.setup_server_env_variables: &setup_server_env_variables
+ - |
+ echo "make server_test_build for app"
+ export LOGIN_GOV_SECRET_KEY=$(echo $E2E_LOGIN_GOV_SECRET_KEY | base64 --decode)
+ export OKTA_CUST_CLIENT_ID=notrealkey
+ export OKTA_CUSTOMER_SECRET_KEY=notrealkey
+ export OKTA_OFFICE_SECRET_KEY=notrealkey1
+ export OKTA_ADMIN_SECRET_KEY=notrealkey2
+ export OKTA_TENANT_ORG_URL=test-milmove.okta.mil
+ export GOTEST_PARALLEL=8
+ export DB_PORT_TEST=5433
+ export DB_NAME=test_db
+ export DB_NAME_TEST=test_db
+ export DTOD_USE_MOCK='true'
+ export ENV=test
+ export ENVIRONMENT=test
+ export SERVER_REPORT=1
+ export COVERAGE=1
+ export SERVE_API_INTERNAL='true'
+ export OKTA_CUSTOMER_CLIENT_ID=1q2w3e4r5t6y7u8i9o
+ export OKTA_ADMIN_CLIENT_ID=AQ1SW2DE3FR4G5
+ export OKTA_OFFICE_CLIENT_ID=9f9f9s8s90gig9
+ export OKTA_API_KEY=notrealapikey8675309
+ export OKTA_OFFICE_GROUP_ID=notrealgroupId
+ export OKTA_CUSTOMER_GROUP_ID=notrealcustomergroupId
sast:
stage: pre_checks
+ tags:
+ - $RUNNER_TAG
include:
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
@@ -151,6 +251,8 @@ include:
anti_virus:
stage: pre_checks
+ tags:
+ - $RUNNER_TAG
image: milmove/clamav-ci # Custom image with ClamAV pre-installed
script:
- pwd
@@ -176,13 +278,33 @@ anti_virus:
rules:
- *check_main
+# Prep the public folder for frontend dependency serving
+# This is needed for things like pdfjs-dist
+prep_server_hosted_client_deps:
+ stage: pre_checks
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ before_script:
+ - *setup_milmove_env
+ script: |
+ echo "Running prep_server_hosted_client_deps"
+ ./scripts/fetch-react-file-viewer-from-yarn
+ after_script:
+ - *announce_failure
+ artifacts:
+ paths:
+ - /builds/milmove/mymove/public
+
pre_deps_golang:
stage: pre_checks
+ tags:
+ - $RUNNER_TAG
image: $DOCKER_APP_IMAGE
before_script:
- *setup_milmove_env
variables:
- KUBERNETES_CPU_REQUEST: "2"
+ KUBERNETES_CPU_REQUEST: "4"
KUBERNETES_MEMORY_REQUEST: "4Gi"
KUBERNETES_MEMORY_LIMIT: "4Gi"
script:
@@ -191,10 +313,12 @@ pre_deps_golang:
- make bin/swagger
after_script:
- *announce_failure
+ cache:
+ - <<: *go_cache
artifacts:
paths:
- - bin/
- - swagger/
+ - /builds/milmove/mymove/bin/
+ - /builds/milmove/mymove/swagger/
#TODO: Optimization potential
# cache:
# key: "$CI_COMMIT_REF_SLUG-go"
@@ -205,23 +329,17 @@ pre_deps_golang:
pre_deps_yarn:
stage: pre_checks
+ tags:
+ - $RUNNER_TAG
image: $DOCKER_APP_IMAGE
- needs:
- - pre_deps_golang
before_script:
- *setup_milmove_env
script:
- - pwd
- - ls bin
- - yarn config set "strict-ssl" false
- - yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
- - scripts/check-generated-code yarn.lock
- - echo "Temporarily skipping yarn installation and code checks."
- artifacts:
- paths:
- - ~/.cache/yarn
+ - *install_yarn
+ cache:
+ - <<: *yarn_cache
after_script:
- - *announce_failure
+ - *announce_failure
check_generated_code:
stage: pre_checks
@@ -241,6 +359,8 @@ check_generated_code:
check_tls_certificate_dp3:
stage: pre_checks
+ tags:
+ - $RUNNER_TAG
image: $DOCKER_APP_IMAGE # Replace with your appropriate Docker image.
before_script:
- *setup_aws_vars_dp3
@@ -263,7 +383,9 @@ check_tls_certificate_dp3:
check_tls_certificate_stg:
stage: pre_checks
- image: $DOCKER_APP_IMAGE # This can reB-18585-gitlab-pipeline-work unchanged, or you can use a lightweight image since no real work is done.
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
before_script:
- *setup_aws_vars_stg
- *setup_tls_vars_stg
@@ -275,6 +397,8 @@ check_tls_certificate_stg:
check_tls_certificate_prd:
stage: pre_checks
+ tags:
+ - $RUNNER_TAG
image: $DOCKER_APP_IMAGE
before_script:
- *setup_tls_vars_prd
@@ -285,28 +409,79 @@ check_tls_certificate_prd:
after_script:
- *announce_failure
+build_storybook:
+ stage: build
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ variables:
+ KUBERNETES_CPU_REQUEST: "4"
+ KUBERNETES_MEMORY_REQUEST: "8Gi"
+ KUBERNETES_MEMORY_LIMIT: "8Gi"
+ needs:
+ - pre_deps_yarn
+ - anti_virus
+ cache:
+ - <<: *yarn_cache
+ before_script:
+ - *setup_milmove_env
+ - *install_yarn
+ script:
+ - yarn build-storybook
+ after_script:
+ - *announce_failure
+ artifacts:
+ paths:
+ - /builds/milmove/mymove/storybook-static
+ rules:
+ - *check_main
+
+deploy_storybook_dp3:
+ stage: deploy
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - build_storybook
+ before_script:
+ - *setup_milmove_env
+ script:
+ - echo "TODO Add steps"
+ - echo "deploy_storybook_dp3"
+ after_script:
+ - *announce_failure
+ artifacts:
+ paths:
+ - /builds/milmove/mymove/storybook-static
+ rules:
+ - *check_main
+
compile_app_client:
stage: build
+ tags:
+ - $RUNNER_TAG
image: $DOCKER_APP_IMAGE
+ cache:
+ - <<: *yarn_cache
variables:
- KUBERNETES_CPU_REQUEST: "2"
+ KUBERNETES_CPU_REQUEST: "6"
KUBERNETES_MEMORY_REQUEST: "8Gi"
KUBERNETES_MEMORY_LIMIT: "8Gi"
- before_script: *setup_milmove_env
+ before_script:
+ - *setup_milmove_env
+ - *install_yarn
needs:
- pre_deps_yarn
script:
- make client_build
- - echo "Skipping actual build steps."
artifacts:
paths:
- - ~/.cache/yarn
- /builds/milmove/mymove/bin
- /builds/milmove/mymove/build
- playwright
- playwright.config.js
- package.json
- - yarn.lock
- eslint-plugin-ato
expire_in: 1 week
after_script:
@@ -315,15 +490,22 @@ compile_app_client:
compile_app_server:
stage: build
+ tags:
+ - $RUNNER_TAG
image: $DOCKER_APP_IMAGE
+ cache:
+ - <<: *go_cache
+ - <<: *yarn_cache
variables:
- KUBERNETES_CPU_REQUEST: "2"
- KUBERNETES_MEMORY_REQUEST: "4Gi"
- KUBERNETES_MEMORY_LIMIT: "4Gi"
+ KUBERNETES_CPU_REQUEST: "6"
+ KUBERNETES_MEMORY_REQUEST: "6Gi"
+ KUBERNETES_MEMORY_LIMIT: "8Gi"
needs:
- pre_deps_golang
- pre_deps_yarn
- before_script: *setup_milmove_env
+ before_script:
+ - *setup_milmove_env
+ - *install_yarn
script:
- make -j 4 server_build build_tools
- echo "Skipping server and tools compilation."
@@ -347,8 +529,621 @@ compile_app_server:
after_script:
- *announce_failure
+
+#####################################
+## Test stages various conditions ##
+#####################################
+
+pre_test:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ cache:
+ - <<: *go_cache
+ - <<: *yarn_cache
+ needs:
+ - pre_deps_golang
+ - pre_deps_yarn
+ - check_tls_certificate_stg
+ - check_tls_certificate_prd
+ variables:
+ KUBERNETES_CPU_REQUEST: "4"
+ KUBERNETES_MEMORY_REQUEST: "6Gi"
+ KUBERNETES_MEMORY_LIMIT: "6Gi"
+ before_script: *setup_milmove_env
+ script:
+ - export GODEBUG=asyncpreemptoff=1
+ - echo "Save Baseline Spectral Lint"
+ - |
+ [ -d ~/transcom/mymove/spectral ] && cp -r ~/transcom/mymove/spectral /tmp/spectral_baseline || echo "Skipping saving baseline"
+ - rm -rf ~/transcom/mymove/spectral
+ - *install_yarn
+ - echo "Run pre-commit tests without golangci-lint, eslint, or prettier"
+ - SKIP=golangci-lint,eslint,prettier,ato-go-linter,gomod,appcontext-linter pre-commit run --all-files
+ - |
+ echo "Run pre-commit tests with ato-go-linter only"
+ pre-commit run -v --all-files ato-go-linter
+ - |
+ echo "Run pre-commit tests with gomod only"
+ pre-commit run -v --all-files gomod,appcontext-linter
+ - |
+ echo "Run pre-commit tests with appcontext-linter only"
+ pre-commit run -v --all-files appcontext-linter
+ - echo "Run pre-commit tests with golangci-lint only"
+ - |
+ echo 'export GOLANGCI_LINT_CONCURRENCY=4' >> $BASH_ENV
+ echo 'export GOLANGCI_LINT_VERBOSE=-v' >> $BASH_ENV
+ source $BASH_ENV
+ mkdir -p tmp/test-results/pretest
+ pre-commit run -v --all-files golangci-lint | tee tmp/test-results/pretest/golangci-lint.out
+ - echo "Run prettier, eslint, danger checks"
+ - yarn prettier-ci
+ - yarn lint
+ - yarn danger ci --failOnErrors
+ - echo "Run spectral linter on all files"
+ - ./scripts/ensure-spectral-lint /tmp/spectral_baseline spectral
+ - ./scripts/pre-commit-go-mod || exit 0
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_server_ignore_branch
+
+server_test:
+ stage: test
+ tags:
+ - $DOCKER_RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_golang
+ before_script:
+ - *setup_milmove_env
+ - *setup_generic_app_env_variables
+ - *setup_server_env_variables
+ services:
+ - name: docker:dind
+ alias: docker
+ - name: $postgres
+ - name: $redis
+ variables:
+ DOCKER_HOST: "tcp://docker-backend.gitlab-runner.svc.cluster.local:2375"
+ DOCKER_TLS_CERTDIR: ""
+ APPLICATION: app
+ # 8 since this runs on xlarge with 8 CPUs
+ GOTEST_PARALLEL: 8
+ DB_PASSWORD: mysecretpassword
+ DB_USER_LOW_PRIV: crud
+ DB_PASSWORD_LOW_PRIV: mysecretpassword
+ DB_USER: postgres
+ DB_HOST: localhost
+ DB_PORT_TEST: 5433
+ DB_PORT: 5432
+ DB_NAME: test_db
+ DB_NAME_TEST: test_db
+ DTOD_USE_MOCK: 'true'
+ MIGRATION_MANIFEST: '/builds/milmove/mymove/migrations/app/migrations_manifest.txt'
+ MIGRATION_PATH: 'file:///builds/milmove/mymove/migrations/app/schema;file:///builds/milmove/mymove/migrations/app/secure'
+ EIA_KEY: db2522a43820268a41a802a16ae9fd26 # dummy key generated with openssl rand -hex 16
+ ENV: test
+ ENVIRONMENT: test
+ SERVER_REPORT: 1
+ COVERAGE: 1
+ SERVE_API_INTERNAL: 'true'
+ OKTA_CUSTOMER_CLIENT_ID: 1q2w3e4r5t6y7u8i9o
+ OKTA_ADMIN_CLIENT_ID: AQ1SW2DE3FR4G5
+ OKTA_OFFICE_CLIENT_ID: 9f9f9s8s90gig9
+ OKTA_API_KEY: notrealapikey8675309
+ OKTA_OFFICE_GROUP_ID: notrealgroupId
+ OKTA_CUSTOMER_GROUP_ID: notrealcustomergroupId
+ script:
+ - psql --version
+ - for i in $(seq 1 5); do go mod download && break || s=$? && sleep 5; done; (exit $s)
+ - scripts/check-generated-code go.sum
+ - make bin/swagger
+ - echo "server test -- TODO Add steps need to potentially pass job id to file and persist"
+ - make -j 2 bin/milmove bin/gotestsum
+ - make server_test for app
+ # - go install gotest.tools/gotestsum@latest
+ # - go mod tidy
+ #- bin/gotestsum --junitfile server_test_report.xml --format server_test
+ artifacts:
+ paths:
+ - /builds/milmove/mymove/bin/gotestsum
+ - /builds/milmove/mymove/tmp/test-results
+ when: always
+ reports:
+ junit: /builds/milmove/mymove/tmp/test-results/gotest/app/go-test-report.xml
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_server_ignore_branch
+
+server_test_coverage:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_golang
+ - server_test
+ before_script: *setup_milmove_env
+ script:
+ - echo "TODO understand recording stats and PR interaction"
+ - echo "server test coverage"
+ - |
+ echo "Ensure Test Coverage Increasing"
+ ./scripts/ensure-go-test-coverage \
+ tmp/baseline-go-coverage/go-coverage.txt \
+ tmp/test-results/gotest/app/go-coverage.txt
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_server_ignore_branch
+ ###may need to rethink the logic and intent of this they save per the following and do some PR interaction
+ # only save the cache on default branch builds because we only want to
+ # change the baseline of test results on main builds
+ #
+ # Save the new baseline regardless of if the coverage succeeds
+ # or fails as a merge to main means we have a new baseline. We
+ # will use other means to measure if our coverage is increasing
+
+client_test:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ variables:
+ KUBERNETES_CPU_REQUEST: "4"
+ KUBERNETES_MEMORY_REQUEST: "8Gi"
+ KUBERNETES_MEMORY_LIMIT: "8Gi"
+ needs:
+ - pre_deps_yarn
+ cache:
+ - <<: *yarn_cache
+ before_script:
+ - *setup_milmove_env
+ - *install_yarn
+ coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
+ dependencies:
+ - pre_deps_yarn
+ script:
+ - echo "client test coverage"
+ - JEST_JUNIT_OUTPUT_DIR=jest-junit-reports yarn test:coverage -results=false >> $CI_PROJECT_DIR/coverage.output
+ artifacts:
+ when: always
+ reports:
+ junit:
+ - jest-junit-reports/junit.xml
+ paths:
+ - /builds/milmove/mymove/coverage
+ - /builds/milmove/mymove/jest-junit-reports
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_client_ignore_branch
+
+client_test_coverage:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - client_test
+ before_script: *setup_milmove_env
+ # TODO: need to add cache for max coverage increase similar to this
+ # https://stackoverflow.com/questions/54542922/force-coverage-increase-in-gitlab-prs
+ script:
+ - echo "TODO understand recording stats and PR interaction"
+ - |
+ echo "Ensure Test Coverage Increasing"
+ ./scripts/ensure-js-test-coverage \
+ tmp/baseline-jest-coverage/clover.xml \
+ coverage/clover.xml
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_client_ignore_branch
+
+integration_test_devseed:
+ stage: test
+ tags:
+ - $DOCKER_RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ services:
+ - name: docker:dind
+ alias: docker
+ - name: $postgres
+ - name: $redis
+ variables:
+ DOCKER_HOST: "tcp://docker-backend.gitlab-runner.svc.cluster.local:2375"
+ DOCKER_TLS_CERTDIR: ""
+ APPLICATION: app
+ DB_PASSWORD: mysecretpassword
+ DB_USER_LOW_PRIV: crud
+ DB_PASSWORD_LOW_PRIV: mysecretpassword
+ DB_USER: postgres
+ DB_HOST: localhost
+ DB_PORT: 5432
+ DB_NAME: dev_db
+ DB_NAME_DEV: dev_db
+ MIGRATION_MANIFEST: '/builds/milmove/mymove/migrations/app/migrations_manifest.txt'
+ MIGRATION_PATH: 'file:///builds/milmove/mymove/migrations/app/schema;file:///builds/milmove/mymove/migrations/app/secure'
+ EIA_KEY: db2522a43820268a41a802a16ae9fd26 # dummy key generated with openssl rand -hex 16
+ ENVIRONMENT: development
+ DOD_CA_PACKAGE: /builds/milmove/mymove/config/tls/milmove-cert-bundle.p7b
+ POSTGRES_PASSWORD: mysecretpassword
+ POSTGRES_DB: test_db
+ needs:
+ - pre_deps_golang
+ - prep_server_hosted_client_deps
+ before_script:
+ - *setup_milmove_env
+ - *setup_generic_app_env_variables
+ - *setup_devseed_env_variables
+ script:
+ - echo "integration_test_devseed"
+ - |
+ export MOVE_MIL_DOD_CA_CERT=$(cat config/tls/devlocal-ca.pem)
+ export MOVE_MIL_DOD_TLS_CERT=$(cat config/tls/devlocal-https.pem)
+ export MOVE_MIL_DOD_TLS_KEY=$(cat config/tls/devlocal-https.key)
+ - make db_dev_fresh
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_integration_ignore_branch
+
+integration_tests:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - pre_deps_golang
+ - compile_app_client
+ - compile_app_server
+ - integration_test_my
+ - integration_test_office
+ - integration_test_admin
+ - integration_test_devseed
+ before_script: *setup_milmove_env
+ script:
+ - echo "TODO Add steps"
+ - echo "integration_tests"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_integration_ignore_branch
+
+integration_test_mtls:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - compile_app_server
+ before_script: *setup_milmove_env
+ script:
+ - echo "TODO Add steps"
+ - echo "integration_test_mtls"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_integration_mtls_ignore_branch
+
+integration_test_admin:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - pre_deps_golang
+ - compile_app_client
+ - compile_app_server
+ before_script: *setup_milmove_env
+ script:
+ - echo "TODO Add steps"
+ - echo "integration_test_admin"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_integration_ignore_branch
+
+integration_test_my:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - pre_deps_golang
+ - compile_app_client
+ - compile_app_server
+ before_script: *setup_milmove_env
+ script:
+ - echo "TODO Add steps"
+ - echo "integration_test_my"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_integration_ignore_branch
+
+integration_test_office:
+ stage: test
+ tags:
+ - $RUNNER_TAG
+ image: $DOCKER_APP_IMAGE
+ needs:
+ - pre_deps_yarn
+ - pre_deps_golang
+ - compile_app_client
+ - compile_app_server
+ before_script: *setup_milmove_env
+ script:
+ - echo "TODO Add steps"
+ - echo "integration_test_office"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_integration_ignore_branch
+
+
+###############################################################
+## DP3 Env push and deploy stages all off of setting dp3 env ##
+###############################################################
+build_push_app_dp3:
+ stage: push
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: gcr.io/kaniko-project/executor:v1.14.0-debug
+ entrypoint: [""]
+ needs:
+ - compile_app_client
+ - compile_app_server
+ before_script:
+ - *setup_aws_vars_dp3
+ - *setup_release_dp3
+ - *kaniko_before_setup
+ script:
+ - echo "Building and Pushing app Docker image..."
+ - /kaniko/executor --context "${CI_PROJECT_DIR}/" --dockerfile "${CI_PROJECT_DIR}/${APP_DOCKER_FILE}" --destination "${ECR_REPOSITORY_URI}/app:$CI_COMMIT_SHORT_SHA"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+build_push_migrations_dp3:
+ stage: push
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: gcr.io/kaniko-project/executor:v1.14.0-debug
+ entrypoint: [""]
+ needs:
+ - compile_app_server
+ - compile_app_client
+ before_script:
+ - *setup_aws_vars_dp3
+ - *setup_release_dp3
+ - *kaniko_before_setup
+ script:
+ - echo "Building and Pushing migrations Docker image..."
+ - /kaniko/executor --context "${CI_PROJECT_DIR}/" --dockerfile "${CI_PROJECT_DIR}/Dockerfile.migrations" --destination "${ECR_REPOSITORY_URI}/app-migrations:$CI_COMMIT_SHORT_SHA"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+build_push_tasks_dp3:
+ stage: push
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: gcr.io/kaniko-project/executor:v1.14.0-debug
+ entrypoint: [""]
+ needs:
+ - compile_app_server
+ - compile_app_client
+ before_script:
+ - *setup_aws_vars_dp3
+ - *setup_release_dp3
+ - *kaniko_before_setup
+ script:
+ - echo "Building tasks Docker image..."
+ - /kaniko/executor --context "${CI_PROJECT_DIR}/" --dockerfile "${CI_PROJECT_DIR}/${TASK_DOCKER_FILE}" --destination "${ECR_REPOSITORY_URI}/app-tasks:$CI_COMMIT_SHORT_SHA"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+push_otel_collector_image_dp3:
+ stage: push
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: $DOCKER_BASE_IMAGE
+ entrypoint: [""]
+ needs:
+ - compile_app_server
+ - compile_app_client
+ script:
+ - echo "Logging in to Amazon ECR with Crane..."
+ - aws ecr get-login-password --region us-gov-west-1 | crane auth login ${ECR_REPOSITORY_URI} -u AWS --password-stdin
+
+ - echo "Pulling the AWS OTel Collector image from the public registry with Crane..."
+ - crane pull --insecure public.ecr.aws/aws-observability/aws-otel-collector:v0.31.0 image.tar
+
+ - echo "Pushing the image to our private ECR using Crane..."
+ - crane push --insecure image.tar ${ECR_REPOSITORY_URI}/otel-collector:${CI_COMMIT_SHORT_SHA}
+
+ - echo "Cleaning up the temporary image file..."
+ - rm image.tar
+ allow_failure: false
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+deploy_migrations_dp3:
+ stage: deploy
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: $DOCKER_APP_IMAGE
+ entrypoint: [""]
+ needs:
+ - build_push_migrations_dp3
+ - compile_app_server
+ - compile_app_client
+ before_script:
+ - *setup_aws_vars_dp3
+ - *setup_release_dp3
+ script:
+ # Step 1: Get the Digest
+ - echo "Getting Digest from AWS"
+ - export ECR_DIGEST=$(aws ecr describe-images --repository-name app-migrations --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
+ # Step 2: Ensure exclusive execution and Snapshot
+ - echo "Snapshotting database"
+ - ./scripts/rds-snapshot-app-db "$APP_ENVIRONMENT"
+ # Step 3: Run migrations
+ - echo "Running migrations"
+ - ./scripts/ecs-run-app-migrations-container "${ECR_REPOSITORY_URI}/app-migrations@${ECR_DIGEST}" "${APP_ENVIRONMENT}"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+deploy_tasks_dp3:
+ stage: deploy
+ tags:
+ - $RUNNER_TAG
+ image:
+ name: $DOCKER_APP_IMAGE
+ entrypoint: [""]
+ needs:
+ - build_push_tasks_dp3
+ - compile_app_server
+ - compile_app_client
+ before_script:
+ - *setup_release_dp3
+ script:
+ - echo "Getting Digest from AWS"
+ - export ECR_DIGEST=$(aws ecr describe-images --repository-name app-tasks --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
+ - echo "Deploying GHC fuel price data task service"
+ - ./scripts/ecs-deploy-task-container save-ghc-fuel-price-data "${ECR_REPOSITORY_URI}/app-tasks@${ECR_DIGEST}" "${APP_ENVIRONMENT}"
+ - echo "Deploying payment reminder email task service"
+ - ./scripts/ecs-deploy-task-container send-payment-reminder "${ECR_REPOSITORY_URI}/app-tasks@${ECR_DIGEST}" "${APP_ENVIRONMENT}"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+deploy_app_client_tls_dp3:
+ stage: deploy
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: $DOCKER_APP_IMAGE
+ entrypoint: [""]
+ needs:
+ - deploy_migrations_dp3
+ - push_otel_collector_image_dp3
+ - compile_app_server
+ - compile_app_client
+ variables:
+ OPEN_TELEMETRY_SIDECAR: "true"
+ HEALTH_CHECK: "true"
+ before_script:
+ - *setup_aws_vars_dp3
+ - *setup_release_dp3
+ script:
+ # - echo "Comparing against deployed commit"
+ # - ./scripts/compare-deployed-commit "" $CI_COMMIT_SHA ${TLS_KEY} ${TLS_CERT} ${TLS_CA}
+ - echo "Getting Digest from AWS"
+ - export ECR_DIGEST=$(aws ecr describe-images --repository-name app --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
+ - echo "Getting otel collector Digest from AWS"
+ - export OTEL_ECR_DIGEST=$(aws ecr describe-images --repository-name otel-collector --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
+ - export OTEL_COLLECTOR_IMAGE="${ECR_REPOSITORY_URI}/otel-collector@${OTEL_ECR_DIGEST}"
+ - echo "Deploying app-client-tls service"
+ - ./scripts/ecs-deploy-service-container app-client-tls "${ECR_REPOSITORY_URI}/app@${ECR_DIGEST}" "${APP_ENVIRONMENT}" "/bin/milmove serve"
+ - echo "Running Health Check"
+ # - bin/health-checker --schemes https --hosts api.demo.dp3.us --key ${TLS_KEY} --cert ${TLS_CERT} --ca ${TLS_CA} --tries 10 --backoff 3 --log-level info --timeout 5m
+ # - echo "Running TLS Check"
+ # - bin/tls-checker --schemes https --hosts api.demo.dp3.us --key ${TLS_KEY} --cert ${TLS_CERT} --ca ${TLS_CA} --log-level info --timeout 15m
+ # - echo "Checking deployed commits"
+ # - ./scripts/check-deployed-commit "api.demo.dp3.us" "$CI_COMMIT_SHA" ${TLS_KEY} ${TLS_CERT} ${TLS_CA}
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+deploy_app_dp3:
+ stage: deploy
+ tags:
+ - $RUNNER_TAG
+ environment: DP3_ENV
+ image:
+ name: $DOCKER_APP_IMAGE
+ entrypoint: [""]
+ needs:
+ - build_push_app_dp3
+ - deploy_migrations_dp3
+ - compile_app_server
+ - compile_app_client
+ variables:
+ OPEN_TELEMETRY_SIDECAR: "true"
+ HEALTH_CHECK: "true"
+ before_script:
+ - *setup_aws_vars_dp3
+ - *setup_release_dp3
+ script:
+ - echo "Comparing against deployed commit"
+ # - ./scripts/compare-deployed-commit "" "$CI_COMMIT_SHA" "$TLS_KEY" "$TLS_CERT" "$TLS_CA"
+ - echo "Creating .go-version file if not already present"
+ - |
+ if [ -f ".go-version" ]; then
+ echo ".go-version already exists, no need to re-create"
+ else
+ GO_VERSION=$(awk '/golang/ { print $2 }' .tool-versions)
+ echo "Creating .go-version using version ${GO_VERSION}"
+ echo $GO_VERSION > .go-version
+ fi
+ - echo "Getting Digest from AWS"
+ - export ECR_DIGEST=$(aws ecr describe-images --repository-name app --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
+ - echo "Getting otel collector digest from AWS"
+ - export OTEL_ECR_DIGEST=$(aws ecr describe-images --repository-name otel-collector --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
+ - export OTEL_COLLECTOR_IMAGE="${ECR_REPOSITORY_URI}/otel-collector@${OTEL_ECR_DIGEST}"
+ - echo "Deploying app service"
+ - ./scripts/ecs-deploy-service-container app "${ECR_REPOSITORY_URI}/app@${ECR_DIGEST}" "${APP_ENVIRONMENT}" "/bin/milmove serve"
+ - echo "Running Health Check"
+ # - bin/health-checker --schemes https --hosts my.demo.dp3.us,office.demo.dp3.us,admin.demo.dp3.us --tries 10 --backoff 3 --log-level info --timeout 5m
+ # - echo "Running TLS Check"
+ # - bin/tls-checker --schemes https --hosts my.demo.dp3.us,office.demo.dp3.us,admin.demo.dp3.us --log-level info --timeout 15m
+ # - echo "Checking deployed commits"
+ - ./scripts/check-deployed-commit "my.demo.dp3.us,office.demo.dp3.us,admin.demo.dp3.us" "$CI_COMMIT_SHA"
+ after_script:
+ - *announce_failure
+ rules:
+ - *check_dp3
+
+########################################################
+## STG push and deploy stages all off of main only ##
+########################################################
+
build_push_app_stg:
stage: push
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: gcr.io/kaniko-project/executor:v1.14.0-debug
@@ -370,6 +1165,8 @@ build_push_app_stg:
build_push_migrations_stg:
stage: push
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: gcr.io/kaniko-project/executor:v1.14.0-debug
@@ -391,6 +1188,8 @@ build_push_migrations_stg:
build_push_tasks_stg:
stage: push
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: gcr.io/kaniko-project/executor:v1.14.0-debug
@@ -412,6 +1211,8 @@ build_push_tasks_stg:
push_otel_collector_image_stg:
stage: push
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: $DOCKER_BASE_IMAGE
@@ -442,6 +1243,8 @@ push_otel_collector_image_stg:
deploy_migrations_stg:
stage: deploy
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: $DOCKER_APP_IMAGE
@@ -470,6 +1273,8 @@ deploy_migrations_stg:
deploy_tasks_stg:
stage: deploy
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: $DOCKER_APP_IMAGE
@@ -533,6 +1338,8 @@ deploy_app_client_tls_stg:
deploy_app_stg:
stage: deploy
+ tags:
+ - $RUNNER_TAG
environment: stg
image:
name: $DOCKER_APP_IMAGE
@@ -578,12 +1385,14 @@ deploy_app_stg:
rules:
- *check_main
+##############################################################################
+## PROD push and deploy stages all dependent on prod_approval manual stage ##
+##############################################################################
prod_approval:
stage: prod_approval
+ tags:
+ - $RUNNER_TAG
environment: prd_approval
- image:
- name: gcr.io/kaniko-project/executor:v1.14.0-debug
- entrypoint: [""]
needs:
- compile_app_client
- compile_app_server
@@ -620,6 +1429,8 @@ build_push_app_prd:
build_push_migrations_prd:
stage: push_prd
+ tags:
+ - $RUNNER_TAG
environment: prd
image:
name: gcr.io/kaniko-project/executor:v1.14.0-debug
@@ -638,11 +1449,13 @@ build_push_migrations_prd:
after_script:
- *announce_failure
rules:
- - if: '$CI_COMMIT_BRANCH == "main"'
+ - *check_main
build_push_tasks_prd:
stage: push_prd
environment: prd
+ tags:
+ - $RUNNER_TAG
image:
name: gcr.io/kaniko-project/executor:v1.14.0-debug
entrypoint: [""]
@@ -664,6 +1477,8 @@ build_push_tasks_prd:
push_otel_collector_image_prd:
stage: push_prd
+ tags:
+ - $RUNNER_TAG
environment: prd
image:
name: $DOCKER_BASE_IMAGE
@@ -691,11 +1506,13 @@ push_otel_collector_image_prd:
after_script:
- *announce_failure
rules:
- - if: '$CI_COMMIT_BRANCH == "main"'
+ - *check_main
deploy_migrations_prd:
stage: deploy_prd
environment: prd
+ tags:
+ - $RUNNER_TAG
image:
name: $DOCKER_APP_IMAGE
entrypoint: [""]
@@ -724,6 +1541,8 @@ deploy_migrations_prd:
deploy_tasks_prd:
stage: deploy_prd
environment: prd
+ tags:
+ - $RUNNER_TAG
image:
name: $DOCKER_APP_IMAGE
entrypoint: [""]
@@ -749,6 +1568,8 @@ deploy_tasks_prd:
deploy_app_client_tls_prd:
stage: deploy_prd
environment: prd
+ tags:
+ - $RUNNER_TAG
image:
name: $DOCKER_APP_IMAGE
entrypoint: [""]
@@ -786,6 +1607,8 @@ deploy_app_client_tls_prd:
deploy_app_prd:
stage: deploy_prd
+ tags:
+ - $RUNNER_TAG
environment: prd
image:
name: $DOCKER_APP_IMAGE
@@ -829,231 +1652,4 @@ deploy_app_prd:
after_script:
- *announce_failure
rules:
- - *check_main
-
-
-build_push_app_dp3:
- stage: push
- environment: DP3_ENV
- image:
- name: gcr.io/kaniko-project/executor:v1.14.0-debug
- entrypoint: [""]
- needs:
- - compile_app_client
- - compile_app_server
- before_script:
- - *setup_aws_vars_dp3
- - *setup_release_dp3
- - *kaniko_before_setup
- script:
- - echo "Building and Pushing app Docker image..."
- - /kaniko/executor --context "${CI_PROJECT_DIR}/" --dockerfile "${CI_PROJECT_DIR}/${APP_DOCKER_FILE}" --destination "${ECR_REPOSITORY_URI}/app:$CI_COMMIT_SHORT_SHA"
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-build_push_migrations_dp3:
- stage: push
- environment: DP3_ENV
- image:
- name: gcr.io/kaniko-project/executor:v1.14.0-debug
- entrypoint: [""]
- needs:
- - compile_app_server
- - compile_app_client
- before_script:
- - *setup_aws_vars_dp3
- - *setup_release_dp3
- - *kaniko_before_setup
- script:
- - echo "Building and Pushing migrations Docker image..."
- - /kaniko/executor --context "${CI_PROJECT_DIR}/" --dockerfile "${CI_PROJECT_DIR}/Dockerfile.migrations" --destination "${ECR_REPOSITORY_URI}/app-migrations:$CI_COMMIT_SHORT_SHA"
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-build_push_tasks_dp3:
- stage: push
- environment: DP3_ENV
- image:
- name: gcr.io/kaniko-project/executor:v1.14.0-debug
- entrypoint: [""]
- needs:
- - compile_app_server
- - compile_app_client
- before_script:
- - *setup_aws_vars_dp3
- - *setup_release_dp3
- - *kaniko_before_setup
- script:
- - echo "Building tasks Docker image..."
- - /kaniko/executor --context "${CI_PROJECT_DIR}/" --dockerfile "${CI_PROJECT_DIR}/${TASK_DOCKER_FILE}" --destination "${ECR_REPOSITORY_URI}/app-tasks:$CI_COMMIT_SHORT_SHA"
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-push_otel_collector_image_dp3:
- stage: push
- environment: DP3_ENV
- image:
- name: $DOCKER_BASE_IMAGE
- entrypoint: [""]
- needs:
- - compile_app_server
- - compile_app_client
- script:
- - echo "Logging in to Amazon ECR with Crane..."
- - aws ecr get-login-password --region us-gov-west-1 | crane auth login ${ECR_REPOSITORY_URI} -u AWS --password-stdin
-
- - echo "Pulling the AWS OTel Collector image from the public registry with Crane..."
- - crane pull --insecure public.ecr.aws/aws-observability/aws-otel-collector:v0.31.0 image.tar
-
- - echo "Pushing the image to our private ECR using Crane..."
- - crane push --insecure image.tar ${ECR_REPOSITORY_URI}/otel-collector:${CI_COMMIT_SHORT_SHA}
-
- - echo "Cleaning up the temporary image file..."
- - rm image.tar
- allow_failure: false
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-deploy_migrations_dp3:
- stage: deploy
- environment: DP3_ENV
- image:
- name: $DOCKER_APP_IMAGE
- entrypoint: [""]
- needs:
- - build_push_migrations_dp3
- - compile_app_server
- - compile_app_client
- before_script:
- - *setup_aws_vars_dp3
- - *setup_release_dp3
- script:
- # Step 1: Get the Digest
- - echo "Getting Digest from AWS"
- - export ECR_DIGEST=$(aws ecr describe-images --repository-name app-migrations --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
- # Step 2: Ensure exclusive execution and Snapshot
- - echo "Snapshotting database"
- - ./scripts/rds-snapshot-app-db "$APP_ENVIRONMENT"
- # Step 3: Run migrations
- - echo "Running migrations"
- - ./scripts/ecs-run-app-migrations-container "${ECR_REPOSITORY_URI}/app-migrations@${ECR_DIGEST}" "${APP_ENVIRONMENT}"
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-deploy_tasks_dp3:
- stage: deploy
- image:
- name: $DOCKER_APP_IMAGE
- entrypoint: [""]
- needs:
- - build_push_tasks_dp3
- - compile_app_server
- - compile_app_client
- before_script:
- - *setup_release_dp3
- script:
- - echo "Getting Digest from AWS"
- - export ECR_DIGEST=$(aws ecr describe-images --repository-name app-tasks --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
- - echo "Deploying GHC fuel price data task service"
- - ./scripts/ecs-deploy-task-container save-ghc-fuel-price-data "${ECR_REPOSITORY_URI}/app-tasks@${ECR_DIGEST}" "${APP_ENVIRONMENT}"
- - echo "Deploying payment reminder email task service"
- - ./scripts/ecs-deploy-task-container send-payment-reminder "${ECR_REPOSITORY_URI}/app-tasks@${ECR_DIGEST}" "${APP_ENVIRONMENT}"
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-deploy_app_client_tls_dp3:
- stage: deploy
- environment: DP3_ENV
- image:
- name: $DOCKER_APP_IMAGE
- entrypoint: [""]
- needs:
- - deploy_migrations_dp3
- - push_otel_collector_image_dp3
- - compile_app_server
- - compile_app_client
- variables:
- OPEN_TELEMETRY_SIDECAR: "true"
- HEALTH_CHECK: "true"
- before_script:
- - *setup_aws_vars_dp3
- - *setup_release_dp3
- script:
- # - echo "Comparing against deployed commit"
- # - ./scripts/compare-deployed-commit "" $CI_COMMIT_SHA ${TLS_KEY} ${TLS_CERT} ${TLS_CA}
- - echo "Getting Digest from AWS"
- - export ECR_DIGEST=$(aws ecr describe-images --repository-name app --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
- - echo "Getting otel collector Digest from AWS"
- - export OTEL_ECR_DIGEST=$(aws ecr describe-images --repository-name otel-collector --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
- - export OTEL_COLLECTOR_IMAGE="${ECR_REPOSITORY_URI}/otel-collector@${OTEL_ECR_DIGEST}"
- - echo "Deploying app-client-tls service"
- - ./scripts/ecs-deploy-service-container app-client-tls "${ECR_REPOSITORY_URI}/app@${ECR_DIGEST}" "${APP_ENVIRONMENT}" "/bin/milmove serve"
- - echo "Running Health Check"
- # - bin/health-checker --schemes https --hosts api.demo.dp3.us --key ${TLS_KEY} --cert ${TLS_CERT} --ca ${TLS_CA} --tries 10 --backoff 3 --log-level info --timeout 5m
- # - echo "Running TLS Check"
- # - bin/tls-checker --schemes https --hosts api.demo.dp3.us --key ${TLS_KEY} --cert ${TLS_CERT} --ca ${TLS_CA} --log-level info --timeout 15m
- # - echo "Checking deployed commits"
- # - ./scripts/check-deployed-commit "api.demo.dp3.us" "$CI_COMMIT_SHA" ${TLS_KEY} ${TLS_CERT} ${TLS_CA}
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
-
-deploy_app_dp3:
- stage: deploy
- environment: DP3_ENV
- image:
- name: $DOCKER_APP_IMAGE
- entrypoint: [""]
- needs:
- - build_push_app_dp3
- - deploy_migrations_dp3
- - compile_app_server
- - compile_app_client
- variables:
- OPEN_TELEMETRY_SIDECAR: "true"
- HEALTH_CHECK: "true"
- before_script:
- - *setup_aws_vars_dp3
- - *setup_release_dp3
- script:
- - echo "Comparing against deployed commit"
- # - ./scripts/compare-deployed-commit "" "$CI_COMMIT_SHA" "$TLS_KEY" "$TLS_CERT" "$TLS_CA"
- - echo "Creating .go-version file if not already present"
- - |
- if [ -f ".go-version" ]; then
- echo ".go-version already exists, no need to re-create"
- else
- GO_VERSION=$(awk '/golang/ { print $2 }' .tool-versions)
- echo "Creating .go-version using version ${GO_VERSION}"
- echo $GO_VERSION > .go-version
- fi
- - echo "Getting Digest from AWS"
- - export ECR_DIGEST=$(aws ecr describe-images --repository-name app --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
- - echo "Getting otel collector digest from AWS"
- - export OTEL_ECR_DIGEST=$(aws ecr describe-images --repository-name otel-collector --image-ids imageTag=$CI_COMMIT_SHORT_SHA --query 'imageDetails[0].imageDigest' --output text)
- - export OTEL_COLLECTOR_IMAGE="${ECR_REPOSITORY_URI}/otel-collector@${OTEL_ECR_DIGEST}"
- - echo "Deploying app service"
- - ./scripts/ecs-deploy-service-container app "${ECR_REPOSITORY_URI}/app@${ECR_DIGEST}" "${APP_ENVIRONMENT}" "/bin/milmove serve"
- - echo "Running Health Check"
- # - bin/health-checker --schemes https --hosts my.demo.dp3.us,office.demo.dp3.us,admin.demo.dp3.us --tries 10 --backoff 3 --log-level info --timeout 5m
- # - echo "Running TLS Check"
- # - bin/tls-checker --schemes https --hosts my.demo.dp3.us,office.demo.dp3.us,admin.demo.dp3.us --log-level info --timeout 15m
- # - echo "Checking deployed commits"
- - ./scripts/check-deployed-commit "my.demo.dp3.us,office.demo.dp3.us,admin.demo.dp3.us" "$CI_COMMIT_SHA"
- after_script:
- - *announce_failure
- rules:
- - *check_dp3
\ No newline at end of file
+ - *check_main
\ No newline at end of file
diff --git a/config/tls/milmove-cert-bundle.p7b b/config/tls/milmove-cert-bundle.p7b
index 9a53bf6c2e9..85eb6a72d7f 100644
Binary files a/config/tls/milmove-cert-bundle.p7b and b/config/tls/milmove-cert-bundle.p7b differ
diff --git a/go.mod b/go.mod
index e528f684f9d..264e97343fa 100644
--- a/go.mod
+++ b/go.mod
@@ -95,10 +95,10 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.28.0
go.opentelemetry.io/otel/trace v1.31.0
go.uber.org/zap v1.27.0
- golang.org/x/crypto v0.27.0
+ golang.org/x/crypto v0.31.0
golang.org/x/net v0.29.0
golang.org/x/oauth2 v0.23.0
- golang.org/x/text v0.18.0
+ golang.org/x/text v0.21.0
golang.org/x/tools v0.24.0
google.golang.org/grpc v1.68.0
gopkg.in/dnaeon/go-vcr.v3 v3.2.0
@@ -261,10 +261,10 @@ require (
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/image v0.18.0 // indirect
golang.org/x/mod v0.20.0 // indirect
- golang.org/x/sync v0.8.0 // indirect
- golang.org/x/sys v0.25.0 // indirect
- golang.org/x/term v0.24.0 // indirect
- google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/term v0.27.0 // indirect
+ google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
diff --git a/go.sum b/go.sum
index edfdd1c49f0..8a725675df2 100644
--- a/go.sum
+++ b/go.sum
@@ -723,8 +723,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
@@ -790,8 +790,8 @@ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -831,8 +831,8 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -849,8 +849,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
-golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -863,8 +863,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt
index 62a07c54465..7e56a0912ee 100644
--- a/migrations/app/migrations_manifest.txt
+++ b/migrations/app/migrations_manifest.txt
@@ -1053,6 +1053,7 @@
20241203024453_add_ppm_max_incentive_column.up.sql
20241204155919_update_ordering_proc.up.sql
20241204210208_retroactive_update_of_ppm_max_and_estimated_incentives_prd.up.sql
+20241209121924_entitlements_refactor.up.sql
20241210143143_redefine_mto_shipment_audit_table.up.sql
20241216170325_update_nts_enum_name.up.sql
20241216190428_update_get_zip_code_function_and_update_pricing_proc.up.sql
@@ -1067,8 +1068,10 @@
20241226173330_add_intl_param_values_to_service_params_table.up.sql
20241227153723_remove_empty_string_emplid_values.up.sql
20241227202424_insert_transportation_offices_camp_pendelton.up.sql
+20241230150644_student_travel_weight_limit_param.up.sql
20241230190638_remove_AK_zips_from_zip3.up.sql
20241230190647_add_missing_AK_zips_to_zip3_distances.up.sql
20250103130619_revert_data_change_for_gbloc_for_ak.up.sql
20250103180420_update_pricing_proc_to_use_local_price_variable.up.sql
20250110153428_add_shipment_address_updates_to_move_history.up.sql
+20250110214012_homesafeconnect_cert.up.sql
diff --git a/migrations/app/schema/20241209121924_entitlements_refactor.up.sql b/migrations/app/schema/20241209121924_entitlements_refactor.up.sql
new file mode 100644
index 00000000000..a8438074776
--- /dev/null
+++ b/migrations/app/schema/20241209121924_entitlements_refactor.up.sql
@@ -0,0 +1,815 @@
+-- See https://dp3.atlassian.net/wiki/spaces/MT/pages/2738716677/HHG+and+UB+Entitlements
+-- Prep entitlements table for holding weight restricted
+ALTER TABLE entitlements
+ADD COLUMN IF NOT EXISTS weight_restriction int;
+-- Create pay grades table to get our static entitlements.go file to be db based
+CREATE TABLE IF NOT EXISTS pay_grades (
+ id uuid PRIMARY KEY NOT NULL,
+ grade text NOT NULL UNIQUE,
+ grade_description text,
+ created_at timestamp NOT NULL DEFAULT NOW(),
+ updated_at timestamp NOT NULL DEFAULT NOW()
+);
+-- Create household goods allowances table
+CREATE TABLE IF NOT EXISTS hhg_allowances (
+ id uuid PRIMARY KEY NOT NULL,
+ pay_grade_id uuid NOT NULL UNIQUE REFERENCES pay_grades(id) ON DELETE CASCADE,
+ total_weight_self int NOT NULL,
+ total_weight_self_plus_dependents int NOT NULL,
+ pro_gear_weight int NOT NULL,
+ pro_gear_weight_spouse int NOT NULL,
+ created_at timestamp NOT NULL DEFAULT NOW(),
+ updated_at timestamp NOT NULL DEFAULT NOW()
+);
+-- Insert Max HHG allowance app value
+-- camel case to match the existing standaloneCrateCap parameter
+INSERT INTO application_parameters (id, parameter_name, parameter_value)
+VALUES (
+ 'D246186B-E93B-4716-B82C-6A38EA5EAB8C',
+ 'maxHhgAllowance',
+ '18000'
+ );
+-- Insert pay_grades and hhg_allowances
+-- ACADEMY_CADET
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '8D8C82EA-EA8F-4D7F-9D84-8D186AB7A7C0',
+ 'ACADEMY_CADET',
+ 'Academy Cadet'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '8A43128C-B080-4D22-9BEA-6F1CBF7F7123',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'ACADEMY_CADET'
+ ),
+ 350,
+ 350,
+ 0,
+ 0
+ );
+-- MIDSHIPMAN
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '63998729-EF74-486E-BEEA-5B519FA3812F',
+ 'MIDSHIPMAN',
+ 'Midshipman'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'C95AA341-9261-4E14-B63B-9A7262FB8EA0',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'MIDSHIPMAN'
+ ),
+ 350,
+ 350,
+ 0,
+ 0
+ );
+-- AVIATION_CADET
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'DF749D7E-5007-43CD-8715-2875D281F817',
+ 'AVIATION_CADET',
+ 'Aviation Cadet'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '23D6DEF4-975E-4075-A4B2-E4DC3DF3D6FF',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'AVIATION_CADET'
+ ),
+ 7000,
+ 8000,
+ 2000,
+ 500
+ );
+-- E_1
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '6CB785D0-CABF-479A-A36D-A6AEC294A4D0',
+ 'E_1',
+ 'Enlisted Grade E_1'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '6CB785D0-CABF-479A-A36D-A6AEC294A4DE',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_1'
+ ),
+ 5000,
+ 8000,
+ 2000,
+ 500
+ );
+-- E_2
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '5F871C82-F259-43CC-9245-A6E18975DDE0',
+ 'E_2',
+ 'Enlisted Grade E_2'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '5F871C82-F259-43CC-9245-A6E18975DDE8',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_2'
+ ),
+ 5000,
+ 8000,
+ 2000,
+ 500
+ );
+-- E_3
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '862EB395-86D1-44AF-AD47-DEC44FBEDA30',
+ 'E_3',
+ 'Enlisted Grade E_3'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '862EB395-86D1-44AF-AD47-DEC44FBEDA3F',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_3'
+ ),
+ 5000,
+ 8000,
+ 2000,
+ 500
+ );
+-- E_4
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'BB55F37C-3165-46BA-AD3F-9A477F699990',
+ 'E_4',
+ 'Enlisted Grade E_4'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'BB55F37C-3165-46BA-AD3F-9A477F699991',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_4'
+ ),
+ 7000,
+ 8000,
+ 2000,
+ 500
+ );
+-- E_5
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '3F142461-DCA5-4A77-9295-92EE93371330',
+ 'E_5',
+ 'Enlisted Grade E_5'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '3F142461-DCA5-4A77-9295-92EE9337133A',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_5'
+ ),
+ 7000,
+ 9000,
+ 2000,
+ 500
+ );
+-- E_6
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '541AEC36-BD9F-4AD2-ABB4-D9B63E29DC80',
+ 'E_6',
+ 'Enlisted Grade E_6'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '541AEC36-BD9F-4AD2-ABB4-D9B63E29DC8C',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_6'
+ ),
+ 8000,
+ 11000,
+ 2000,
+ 500
+ );
+-- E_7
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '523D57A1-529C-4DFD-8C33-9CB169FD29A0',
+ 'E_7',
+ 'Enlisted Grade E_7'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '523D57A1-529C-4DFD-8C33-9CB169FD29AF',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_7'
+ ),
+ 11000,
+ 13000,
+ 2000,
+ 500
+ );
+-- E_8
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '1D909DB0-602F-4724-BD43-8F90A6660460',
+ 'E_8',
+ 'Enlisted Grade E_8'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '1D909DB0-602F-4724-BD43-8F90A666046E',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_8'
+ ),
+ 12000,
+ 14000,
+ 2000,
+ 500
+ );
+-- E_9
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'A5FC8FD2-6F91-492B-ABE2-2157D03EC990',
+ 'E_9',
+ 'Enlisted Grade E_9'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'A5FC8FD2-6F91-492B-ABE2-2157D03EC99B',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_9'
+ ),
+ 13000,
+ 15000,
+ 2000,
+ 500
+ );
+-- E_9 Special Senior Enlisted
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '911208CC-3D13-49D6-9478-B0A3943435C0',
+ 'E_9_SPECIAL_SENIOR_ENLISTED',
+ 'Enlisted Grade E_9 Special Senior Enlisted'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'D219899B-251F-49E9-94B3-C073C22D9D2F',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'E_9_SPECIAL_SENIOR_ENLISTED'
+ ),
+ 14000,
+ 17000,
+ 2000,
+ 500
+ );
+-- O_1 (Academy Graduate) / W_1 uses same as O_1
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'B25998F4-4715-4F41-8986-4C5C8E59FC80',
+ 'O_1_ACADEMY_GRADUATE',
+ 'Officer Grade O_1 Academy Graduate'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'B25998F4-4715-4F41-8986-4C5C8E59FC84',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_1_ACADEMY_GRADUATE'
+ ),
+ 10000,
+ 12000,
+ 2000,
+ 500
+ );
+-- O_2
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'D1B76A01-D8E4-4BD3-98FF-FA93FF7BC790',
+ 'O_2',
+ 'Officer Grade O_2'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'D1B76A01-D8E4-4BD3-98FF-FA93FF7BC79A',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_2'
+ ),
+ 12500,
+ 13500,
+ 2000,
+ 500
+ );
+-- O_3
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '5658D67B-D510-4226-9E56-714403BA0F10',
+ 'O_3',
+ 'Officer Grade O_3'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '5658D67B-D510-4226-9E56-714403BA0F1D',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_3'
+ ),
+ 13000,
+ 14500,
+ 2000,
+ 500
+ );
+-- O_4
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'E83D8F8D-F70B-4DB1-99CC-DD983D2FD250',
+ 'O_4',
+ 'Officer Grade O_4'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '0991ABBC-5400-4E6C-8BC4-195F9A602E75',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_4'
+ ),
+ 14000,
+ 17000,
+ 2000,
+ 500
+ );
+-- O_5
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '3BC4B197-7897-4105-80A1-39A0378D7730',
+ 'O_5',
+ 'Officer Grade O_5'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'E83D8F8D-F70B-4DB1-99CC-DD983D2FD25D',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_5'
+ ),
+ 16000,
+ 17500,
+ 2000,
+ 500
+ );
+-- O_6
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '455A112D-D1E0-4559-81E8-6DF664638F70',
+ 'O_6',
+ 'Officer Grade O_6'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '3BC4B197-7897-4105-80A1-39A0378D773E',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_6'
+ ),
+ 18000,
+ 18000,
+ 2000,
+ 500
+ );
+-- O_7
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'CF664124-9BAF-4187-8F28-0908C0F0A5E0',
+ 'O_7',
+ 'Officer Grade O_7'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '455A112D-D1E0-4559-81E8-6DF664638F7C',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_7'
+ ),
+ 18000,
+ 18000,
+ 2000,
+ 500
+ );
+-- O_8
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '6E50B04A-52DC-45C9-91D9-4A7B4FA1AB20',
+ 'O_8',
+ 'Officer Grade O_8'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'CF664124-9BAF-4187-8F28-0908C0F0A5E8',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_8'
+ ),
+ 18000,
+ 18000,
+ 2000,
+ 500
+ );
+-- O_9
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '1D6E34C3-8C6C-4D4F-8B91-F46BED3F5E80',
+ 'O_9',
+ 'Officer Grade O_9'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '6E50B04A-52DC-45C9-91D9-4A7B4FA1AB2A',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_9'
+ ),
+ 18000,
+ 18000,
+ 2000,
+ 500
+ );
+-- O_10
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '7FA938AB-1C34-4666-A878-9B989C916D1A',
+ 'O_10',
+ 'Officer Grade O_10'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '1D6E34C3-8C6C-4D4F-8B91-F46BED3F5E85',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'O_10'
+ ),
+ 18000,
+ 18000,
+ 2000,
+ 500
+ );
+-- W_1
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '6BADF8A0-B0EF-4E42-B827-7F63A3987A4B',
+ 'W_1',
+ 'Warrant Officer W_1'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '16F0F64F-728A-42A7-98B7-EA9BF289FE1A',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'W_1'
+ ),
+ 10000,
+ 12000,
+ 2000,
+ 500
+ );
+-- W_2
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'A687A2E1-488C-4943-B9D9-3D645A2712F4',
+ 'W_2',
+ 'Warrant Officer W_2'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'A687A2E1-488C-4943-B9D9-3D645A2712F9',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'W_2'
+ ),
+ 12500,
+ 13500,
+ 2000,
+ 500
+ );
+-- W_3
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '5A65FB1F-4245-4178-B6A7-CC504C9CBB37',
+ 'W_3',
+ 'Warrant Officer W_3'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '5A65FB1F-4245-4178-B6A7-CC504C9CBB38',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'W_3'
+ ),
+ 13000,
+ 14500,
+ 2000,
+ 500
+ );
+-- W_4
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '74DB5649-CF66-4AF8-939B-D3D7F1F6B7C6',
+ 'W_4',
+ 'Warrant Officer W_4'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '74DB5649-CF66-4AF8-939B-D3D7F1F6B7C7',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'W_4'
+ ),
+ 14000,
+ 17000,
+ 2000,
+ 500
+ );
+-- W_5
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ 'EA8CB0E9-15FF-43B4-9E41-7168D01E7553',
+ 'W_5',
+ 'Warrant Officer W_5'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ 'EA8CB0E9-15FF-43B4-9E41-7168D01E7554',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'W_5'
+ ),
+ 16000,
+ 17500,
+ 2000,
+ 500
+ );
+-- CIVILIAN EMPLOYEE
+INSERT INTO pay_grades (id, grade, grade_description)
+VALUES (
+ '9E2CB9A5-ACE3-4235-9EE7-EBE4CC2A9BC9',
+ 'CIVILIAN_EMPLOYEE',
+ 'Civilian Employee'
+ );
+INSERT INTO hhg_allowances (
+ id,
+ pay_grade_id,
+ total_weight_self,
+ total_weight_self_plus_dependents,
+ pro_gear_weight,
+ pro_gear_weight_spouse
+ )
+VALUES (
+ '9E2CB9A5-ACE3-4235-9EE7-EBE4CC2A9BC1',
+ (
+ SELECT id
+ FROM pay_grades
+ WHERE grade = 'CIVILIAN_EMPLOYEE'
+ ),
+ 18000,
+ 18000,
+ 2000,
+ 500
+ );
\ No newline at end of file
diff --git a/migrations/app/schema/20241230150644_student_travel_weight_limit_param.up.sql b/migrations/app/schema/20241230150644_student_travel_weight_limit_param.up.sql
new file mode 100644
index 00000000000..5edefb66caa
--- /dev/null
+++ b/migrations/app/schema/20241230150644_student_travel_weight_limit_param.up.sql
@@ -0,0 +1,16 @@
+-- Prep app param table for json storage
+ALTER TABLE application_parameters
+ADD COLUMN IF NOT EXISTS parameter_json JSONB;
+
+-- Insert one-off student travel app param value for weight limits
+INSERT INTO application_parameters (id, parameter_name, parameter_json)
+VALUES (
+ '4BEEAE29-C074-4CB6-B4AE-F222F755733C',
+ 'studentTravelHhgAllowance',
+ '{
+ "TotalWeightSelf": 350,
+ "TotalWeightSelfPlusDependents": 350,
+ "ProGearWeight": 0,
+ "ProGearWeightSpouse": 0
+ }'::jsonb
+ );
\ No newline at end of file
diff --git a/migrations/app/secure/20250110214012_homesafeconnect_cert.up.sql b/migrations/app/secure/20250110214012_homesafeconnect_cert.up.sql
new file mode 100644
index 00000000000..f9862f58a7c
--- /dev/null
+++ b/migrations/app/secure/20250110214012_homesafeconnect_cert.up.sql
@@ -0,0 +1,4 @@
+-- Local test migration.
+-- This will be run on development environments.
+-- It should mirror what you intend to apply on prd/stg/exp/demo
+-- DO NOT include any sensitive data.
diff --git a/package.json b/package.json
index c3bff3b6b4c..222b9519685 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,7 @@
"reselect": "^4.1.8",
"sass": "^1.77.6",
"swagger-client": "^3.18.5",
- "swagger-ui-dist": "^5.2.0",
+ "swagger-ui-dist": "^5.18.2",
"uswds": "2.13.3",
"uuid": "^9.0.0",
"webpack": "5",
diff --git a/pkg/factory/entitlement_factory.go b/pkg/factory/entitlement_factory.go
index 235fdaf3be6..17aff299990 100644
--- a/pkg/factory/entitlement_factory.go
+++ b/pkg/factory/entitlement_factory.go
@@ -1,6 +1,9 @@
package factory
import (
+ "fmt"
+ "log"
+
"github.com/gobuffalo/pop/v6"
"github.com/transcom/mymove/pkg/gen/internalmessages"
@@ -46,7 +49,6 @@ func BuildEntitlement(db *pop.Connection, customs []Customization, traits []Trai
ocie := true
proGearWeight := 2000
proGearWeightSpouse := 500
- ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
// Create default Entitlement
entitlement := models.Entitlement{
@@ -61,7 +63,30 @@ func BuildEntitlement(db *pop.Connection, customs []Customization, traits []Trai
OrganizationalClothingAndIndividualEquipment: ocie,
}
// Set default calculated values
- entitlement.SetWeightAllotment(string(*grade), ordersType)
+ var hhgAllowance models.HHGAllowance
+ if db != nil && grade != nil {
+ err := db.
+ RawQuery(`
+ SELECT hhg_allowances.*
+ FROM hhg_allowances
+ INNER JOIN pay_grades ON hhg_allowances.pay_grade_id = pay_grades.id
+ WHERE pay_grades.grade = $1
+ LIMIT 1
+ `, grade).
+ First(&hhgAllowance)
+ if err != nil {
+ // The database must not be running or the data was truncated
+ log.Panic(fmt.Errorf("database is not configured properly and is missing static hhg allowance and pay grade data. pay grade: %s err: %w", *order.Grade, err))
+ }
+ }
+
+ allotment := models.WeightAllotment{
+ TotalWeightSelf: hhgAllowance.TotalWeightSelf,
+ TotalWeightSelfPlusDependents: hhgAllowance.TotalWeightSelfPlusDependents,
+ ProGearWeight: hhgAllowance.ProGearWeight,
+ ProGearWeightSpouse: hhgAllowance.ProGearWeightSpouse,
+ }
+ entitlement.WeightAllotted = &allotment
entitlement.DBAuthorizedWeight = entitlement.AuthorizedWeight()
// Overwrite default values with those from custom Entitlement
diff --git a/pkg/factory/entitlement_factory_test.go b/pkg/factory/entitlement_factory_test.go
index 0c6a0adee52..3ece040f039 100644
--- a/pkg/factory/entitlement_factory_test.go
+++ b/pkg/factory/entitlement_factory_test.go
@@ -5,9 +5,12 @@ import (
"github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services/entitlements"
)
func (suite *FactorySuite) TestBuildEntitlement() {
+ fetcher := entitlements.NewWeightAllotmentFetcher()
+
suite.Run("Successful creation of default entitlement", func() {
// Under test: BuildEntitlement
// Mocked: None
@@ -27,7 +30,10 @@ func (suite *FactorySuite) TestBuildEntitlement() {
RequiredMedicalEquipmentWeight: 1000,
OrganizationalClothingAndIndividualEquipment: true,
}
- defEnt.SetWeightAllotment("E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := fetcher.GetWeightAllotment(suite.AppContextForTest(), "E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ defEnt.WeightAllotted = &allotment
+
defEnt.DBAuthorizedWeight = defEnt.AuthorizedWeight()
// FUNCTION UNDER TEST
@@ -84,7 +90,9 @@ func (suite *FactorySuite) TestBuildEntitlement() {
suite.Equal(custEnt.OrganizationalClothingAndIndividualEquipment, entitlement.OrganizationalClothingAndIndividualEquipment)
// Set the weight allotment on the custom object so as to compare
- custEnt.SetWeightAllotment("E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := fetcher.GetWeightAllotment(suite.AppContextForTest(), "E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ custEnt.WeightAllotted = &allotment
custEnt.DBAuthorizedWeight = custEnt.AuthorizedWeight()
// Check that the created object had the correct allotments set
@@ -129,9 +137,10 @@ func (suite *FactorySuite) TestBuildEntitlement() {
testEnt := BuildEntitlement(nil, nil, nil)
// Set the weight allotment on the custom object to O_9
testEnt.DBAuthorizedWeight = nil // clear original value
- testEnt.SetWeightAllotment("O_9", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := fetcher.GetWeightAllotment(suite.AppContextForTest(), "O_9", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ testEnt.WeightAllotted = &allotment
testEnt.DBAuthorizedWeight = testEnt.AuthorizedWeight()
- // Now DBAuthorizedWeight should be appropriate for O_9 grade
// FUNCTION UNDER TEST
grade := internalmessages.OrderPayGrade(models.ServiceMemberGradeO9)
diff --git a/pkg/factory/order_factory.go b/pkg/factory/order_factory.go
index 9bc3c61fb1d..25adb96eb78 100644
--- a/pkg/factory/order_factory.go
+++ b/pkg/factory/order_factory.go
@@ -1,6 +1,7 @@
package factory
import (
+ "fmt"
"log"
"time"
@@ -291,7 +292,25 @@ func buildOrderWithBuildType(db *pop.Connection, customs []Customization, traits
testdatagen.MergeModels(&order, cOrder)
// If db is false, it's a stub. No need to create in database
- if db != nil {
+ if db != nil && order.Grade != nil {
+ // Check if PayGrade already exists
+ var existingPayGrade models.PayGrade
+ err := db.Where("grade = ?", string(*order.Grade)).First(&existingPayGrade)
+ if err == nil {
+ // PayGrade exists
+ grade := internalmessages.OrderPayGrade(existingPayGrade.Grade)
+ order.Grade = internalmessages.NewOrderPayGrade(grade)
+ } else {
+ log.Panic(fmt.Errorf("database is not configured properly and is missing static hhg allowance and pay grade data. pay grade: %s err: %w", *order.Grade, err))
+ }
+
+ // Check if HHGAllowance already exists for this PayGrade
+ var existingHHGAllowance models.HHGAllowance
+ err = db.Where("pay_grade_id = ?", existingPayGrade.ID).First(&existingHHGAllowance)
+ if err != nil {
+ log.Panic(fmt.Errorf("database is not configured properly and is missing static hhg allowance and pay grade data. pay grade: %s err: %w", *order.Grade, err))
+ }
+
mustCreate(db, &order)
}
diff --git a/pkg/factory/shared.go b/pkg/factory/shared.go
index 037f2d352d5..eed57d130ec 100644
--- a/pkg/factory/shared.go
+++ b/pkg/factory/shared.go
@@ -53,6 +53,8 @@ var CustomerSupportRemark CustomType = "CustomerSupportRemark"
var Document CustomType = "Document"
var DutyLocation CustomType = "DutyLocation"
var Entitlement CustomType = "Entitlement"
+var HHGAllowance CustomType = "HHGAllowance"
+var PayGrade CustomType = "PayGrade"
var UBAllowance CustomType = "UBAllowances"
var EvaluationReport CustomType = "EvaluationReport"
var LineOfAccounting CustomType = "LineOfAccounting"
@@ -121,6 +123,8 @@ var defaultTypesMap = map[string]CustomType{
"models.Document": Document,
"models.DutyLocation": DutyLocation,
"models.Entitlement": Entitlement,
+ "models.PayGrade": PayGrade,
+ "models.HHGAllowance": HHGAllowance,
"models.UBAllowances": UBAllowance,
"models.EvaluationReport": EvaluationReport,
"models.LineOfAccounting": LineOfAccounting,
diff --git a/pkg/gen/internalapi/embedded_spec.go b/pkg/gen/internalapi/embedded_spec.go
index 0e198c6c4e6..9597705d4b0 100644
--- a/pkg/gen/internalapi/embedded_spec.go
+++ b/pkg/gen/internalapi/embedded_spec.go
@@ -555,6 +555,9 @@ func init() {
"schema": {
"$ref": "#/definitions/IndexEntitlements"
}
+ },
+ "500": {
+ "description": "internal server error"
}
}
}
@@ -9247,6 +9250,9 @@ func init() {
"schema": {
"$ref": "#/definitions/IndexEntitlements"
}
+ },
+ "500": {
+ "description": "internal server error"
}
}
}
diff --git a/pkg/gen/internalapi/internaloperations/entitlements/index_entitlements_responses.go b/pkg/gen/internalapi/internaloperations/entitlements/index_entitlements_responses.go
index 972c901ef1d..a9358ff2691 100644
--- a/pkg/gen/internalapi/internaloperations/entitlements/index_entitlements_responses.go
+++ b/pkg/gen/internalapi/internaloperations/entitlements/index_entitlements_responses.go
@@ -60,3 +60,28 @@ func (o *IndexEntitlementsOK) WriteResponse(rw http.ResponseWriter, producer run
panic(err) // let the recovery middleware deal with this
}
}
+
+// IndexEntitlementsInternalServerErrorCode is the HTTP code returned for type IndexEntitlementsInternalServerError
+const IndexEntitlementsInternalServerErrorCode int = 500
+
+/*
+IndexEntitlementsInternalServerError internal server error
+
+swagger:response indexEntitlementsInternalServerError
+*/
+type IndexEntitlementsInternalServerError struct {
+}
+
+// NewIndexEntitlementsInternalServerError creates IndexEntitlementsInternalServerError with default headers values
+func NewIndexEntitlementsInternalServerError() *IndexEntitlementsInternalServerError {
+
+ return &IndexEntitlementsInternalServerError{}
+}
+
+// WriteResponse to the client
+func (o *IndexEntitlementsInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
+
+ rw.WriteHeader(500)
+}
diff --git a/pkg/handlers/ghcapi/api.go b/pkg/handlers/ghcapi/api.go
index 3c4f3740941..cf3a4c188c9 100644
--- a/pkg/handlers/ghcapi/api.go
+++ b/pkg/handlers/ghcapi/api.go
@@ -14,6 +14,7 @@ import (
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
dateservice "github.com/transcom/mymove/pkg/services/calendar"
customerserviceremarks "github.com/transcom/mymove/pkg/services/customer_support_remarks"
+ "github.com/transcom/mymove/pkg/services/entitlements"
evaluationreport "github.com/transcom/mymove/pkg/services/evaluation_report"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
@@ -59,6 +60,7 @@ import (
// NewGhcAPIHandler returns a handler for the GHC API
func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
+ waf := entitlements.NewWeightAllotmentFetcher()
ghcSpec, err := loads.Analyzed(ghcapi.SwaggerJSON, "")
if err != nil {
log.Fatalln(err)
@@ -185,7 +187,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
HandlerConfig: handlerConfig,
EvaluationReportFetcher: evaluationreport.NewEvaluationReportFetcher(),
MTOShipmentFetcher: mtoshipment.NewMTOShipmentFetcher(),
- OrderFetcher: order.NewOrderFetcher(),
+ OrderFetcher: order.NewOrderFetcher(waf),
ReportViolationFetcher: reportviolation.NewReportViolationFetcher(),
}
@@ -240,7 +242,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
fetch.NewFetcher(queryBuilder),
handlerConfig.HHGPlanner(),
moveRouter,
- move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()),
+ move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf),
handlerConfig.NotificationSender(),
paymentRequestShipmentRecalculator,
addressUpdater,
@@ -295,7 +297,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
ghcAPI.MoveTaskOrderGetMoveTaskOrderHandler = GetMoveTaskOrderHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
ghcAPI.MoveSetFinancialReviewFlagHandler = SetFinancialReviewFlagHandler{
handlerConfig,
@@ -315,7 +317,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
}
ghcAPI.OrderGetOrderHandler = GetOrdersHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
}
ghcAPI.OrderCounselingUpdateOrderHandler = CounselingUpdateOrderHandler{
handlerConfig,
@@ -323,6 +325,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
}
ghcAPI.OrderCreateOrderHandler = CreateOrderHandler{
handlerConfig,
+ waf,
}
ghcAPI.OrderUpdateOrderHandler = UpdateOrderHandler{
@@ -426,7 +429,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
mtoshipment.NewShipmentRouter(),
mtoServiceItemCreator,
handlerConfig.HHGPlanner(),
- move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()),
+ move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf),
),
shipmentSITStatus,
}
@@ -473,7 +476,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
fetch.NewFetcher(queryBuilder),
handlerConfig.HHGPlanner(),
moveRouter,
- move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()),
+ move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf),
handlerConfig.NotificationSender(),
paymentRequestShipmentRecalculator,
addressUpdater,
@@ -485,7 +488,7 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
fetch.NewFetcher(queryBuilder),
handlerConfig.HHGPlanner(),
moveRouter,
- move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()),
+ move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf),
handlerConfig.NotificationSender(),
paymentRequestShipmentRecalculator,
addressUpdater,
@@ -556,21 +559,21 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
ghcAPI.QueuesGetMovesQueueHandler = GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
movelocker.NewMoveUnlocker(),
officeusercreator.NewOfficeUserFetcherPop(),
}
ghcAPI.QueuesGetDestinationRequestsQueueHandler = GetDestinationRequestsQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
movelocker.NewMoveUnlocker(),
officeusercreator.NewOfficeUserFetcherPop(),
}
ghcAPI.QueuesListPrimeMovesHandler = ListPrimeMovesHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
ghcAPI.QueuesGetPaymentRequestsQueueHandler = GetPaymentRequestsQueueHandler{
@@ -582,14 +585,14 @@ func NewGhcAPIHandler(handlerConfig handlers.HandlerConfig) *ghcops.MymoveAPI {
ghcAPI.QueuesGetServicesCounselingQueueHandler = GetServicesCounselingQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
movelocker.NewMoveUnlocker(),
officeusercreator.NewOfficeUserFetcherPop(),
}
ghcAPI.QueuesGetServicesCounselingOriginListHandler = GetServicesCounselingOriginListHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
officeusercreator.NewOfficeUserFetcherPop(),
}
diff --git a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go
index 882f947c440..813bb11b112 100644
--- a/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go
+++ b/pkg/handlers/ghcapi/internal/payloads/model_to_payload.go
@@ -629,9 +629,6 @@ func Order(order *models.Order) *ghcmessages.Order {
destinationDutyLocation := DutyLocation(&order.NewDutyLocation)
originDutyLocation := DutyLocation(order.OriginDutyLocation)
- if order.Grade != nil && order.Entitlement != nil {
- order.Entitlement.SetWeightAllotment(string(*order.Grade), order.OrdersType)
- }
entitlements := Entitlement(order.Entitlement)
var deptIndicator ghcmessages.DeptIndicator
diff --git a/pkg/handlers/ghcapi/move_task_order_test.go b/pkg/handlers/ghcapi/move_task_order_test.go
index e93d756cf58..a156eb19251 100644
--- a/pkg/handlers/ghcapi/move_task_order_test.go
+++ b/pkg/handlers/ghcapi/move_task_order_test.go
@@ -30,6 +30,7 @@ import (
"github.com/transcom/mymove/pkg/notifications"
routemocks "github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/mocks"
moverouter "github.com/transcom/mymove/pkg/services/move"
@@ -44,7 +45,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrderHandlerIntegration() {
moveTaskOrder := factory.BuildMove(suite.DB(), nil, nil)
factory.FetchReServiceByCode(suite.DB(), models.ReServiceCodeMS)
factory.FetchReServiceByCode(suite.DB(), models.ReServiceCodeCS)
-
+ waf := entitlements.NewWeightAllotmentFetcher()
request := httptest.NewRequest("GET", "/move-task-orders/{moveTaskOrderID}", nil)
params := movetaskorderops.GetMoveTaskOrderParams{
HTTPRequest: request,
@@ -53,7 +54,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrderHandlerIntegration() {
handlerConfig := suite.HandlerConfig()
handler := GetMoveTaskOrderHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
// Validate incoming payload: no body to validate
diff --git a/pkg/handlers/ghcapi/moving_expense_test.go b/pkg/handlers/ghcapi/moving_expense_test.go
index 06c8d03cfc6..5d7e1b8f3a9 100644
--- a/pkg/handlers/ghcapi/moving_expense_test.go
+++ b/pkg/handlers/ghcapi/moving_expense_test.go
@@ -236,7 +236,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
var ppmShipment models.PPMShipment
var movingExpense models.MovingExpense
- suite.PreloadData(func() {
+ setupData := func() {
var err error
userUploader, err = uploader.NewUserUploader(suite.createS3HandlerConfig().FileStorer(), uploader.MaxCustomerUserUploadFileSizeLimit)
@@ -270,7 +270,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
}, nil)
ppmShipment.MovingExpenses = append(ppmShipment.MovingExpenses, movingExpense)
- })
+ }
setUpRequestAndParams := func(movingExpense models.MovingExpense) movingexpenseops.UpdateMovingExpenseParams {
endpoint := fmt.Sprintf("/ppm-shipments/%s/moving-expense/%s", ppmShipment.ID.String(), movingExpense.ID.String())
@@ -330,6 +330,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
suite.Run("Success", func() {
suite.Run("Can approve a moving expense", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
params.UpdateMovingExpense.Status = ghcmessages.PPMDocumentStatusAPPROVED
@@ -352,6 +353,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Can exclude a moving expense", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
reason := "Not a valid receipt"
@@ -380,6 +382,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Can reject a moving expense", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
reason := "Over budget!"
@@ -408,6 +411,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Can update a non-storage moving expense", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
newAmount := movingExpense.Amount.AddCents(1000)
@@ -435,6 +439,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Can update a storage moving expense", func() {
+ setupData()
storageExpenseType := models.MovingExpenseReceiptTypeStorage
storageMovingExpense := factory.BuildMovingExpense(suite.DB(), []factory.Customization{
{
@@ -503,6 +508,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
suite.Run("Failure", func() {
suite.Run("Returns a Forbidden response if the request doesn't come from the office app", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
params.HTTPRequest = suite.AuthenticateRequest(params.HTTPRequest, ppmShipment.Shipment.MoveTaskOrder.Orders.ServiceMember)
@@ -515,6 +521,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Returns a NotFound response when the moving expense is not found", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
params.MovingExpenseID = handlers.FmtUUIDValue(uuid.Must(uuid.NewV4()))
@@ -527,6 +534,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Returns a PreconditionFailed response when the eTag doesn't match the expected eTag", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
params.IfMatch = "wrong eTag"
@@ -547,6 +555,7 @@ func (suite *HandlerSuite) TestUpdateMovingExpenseHandlerIntegration() {
})
suite.Run("Returns an UnprocessableEntity response when the requested updates aren't valid", func() {
+ setupData()
params := setUpRequestAndParams(ppmShipment.MovingExpenses[0])
params.UpdateMovingExpense = &ghcmessages.UpdateMovingExpense{
diff --git a/pkg/handlers/ghcapi/mto_service_items_test.go b/pkg/handlers/ghcapi/mto_service_items_test.go
index 0a38a489ba1..a0b1880ac26 100644
--- a/pkg/handlers/ghcapi/mto_service_items_test.go
+++ b/pkg/handlers/ghcapi/mto_service_items_test.go
@@ -20,6 +20,7 @@ import (
routemocks "github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -304,7 +305,7 @@ func (suite *HandlerSuite) createServiceItem() (models.MTOServiceItem, models.Mo
}
func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandler() {
-
+ waf := entitlements.NewWeightAllotmentFetcher()
builder := query.NewQueryBuilder()
fetcher := fetch.NewFetcher(builder)
planner := &routemocks.Planner{}
@@ -315,7 +316,7 @@ func (suite *HandlerSuite) TestUpdateMTOServiceItemStatusHandler() {
false,
false,
).Return(400, nil)
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -736,6 +737,8 @@ func (suite *HandlerSuite) TestGetMTOServiceItemHandler() {
func (suite *HandlerSuite) TestUpdateServiceItemSitEntryDateHandler() {
serviceItemID := uuid.Must(uuid.FromString("f7b4b9e2-04e8-4c34-827a-df917e69caf4"))
+ waf := entitlements.NewWeightAllotmentFetcher()
+
var requestUser models.User
newSitEntryDate := time.Date(2023, time.October, 10, 10, 10, 0, 0, time.UTC)
@@ -768,7 +771,7 @@ func (suite *HandlerSuite) TestUpdateServiceItemSitEntryDateHandler() {
false,
false,
).Return(400, nil)
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
diff --git a/pkg/handlers/ghcapi/mto_shipment_test.go b/pkg/handlers/ghcapi/mto_shipment_test.go
index 316a2adbbd4..21bddbcf663 100644
--- a/pkg/handlers/ghcapi/mto_shipment_test.go
+++ b/pkg/handlers/ghcapi/mto_shipment_test.go
@@ -24,6 +24,7 @@ import (
"github.com/transcom/mymove/pkg/services"
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -579,6 +580,8 @@ func (suite *HandlerSuite) TestGetShipmentHandler() {
}
func (suite *HandlerSuite) TestApproveShipmentHandler() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
suite.Run("Returns 200 when all validations pass", func() {
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
shipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{
@@ -598,7 +601,7 @@ func (suite *HandlerSuite) TestApproveShipmentHandler() {
builder := query.NewQueryBuilder()
moveRouter := moveservices.NewMoveRouter()
planner := &routemocks.Planner{}
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
planner.On("ZipTransitDistance",
mock.AnythingOfType("*appcontext.appContext"),
mock.Anything,
@@ -2093,6 +2096,7 @@ func (suite *HandlerSuite) TestRequestShipmentCancellationHandler() {
func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
addressUpdater := address.NewAddressUpdater()
addressCreator := address.NewAddressCreator()
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("Returns 200 when all validations pass", func() {
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -2129,7 +2133,7 @@ func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2189,7 +2193,7 @@ func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2246,7 +2250,7 @@ func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2304,7 +2308,7 @@ func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2363,7 +2367,7 @@ func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2421,7 +2425,7 @@ func (suite *HandlerSuite) TestRequestShipmentReweighHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2689,6 +2693,8 @@ func (suite *HandlerSuite) TestReviewShipmentAddressUpdateHandler() {
}
func (suite *HandlerSuite) TestApproveSITExtensionHandler() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
suite.Run("Returns 200 and updates SIT days allowance when validations pass", func() {
sitDaysAllowance := 20
move := factory.BuildApprovalsRequestedMove(suite.DB(), []factory.Customization{
@@ -2760,7 +2766,7 @@ func (suite *HandlerSuite) TestApproveSITExtensionHandler() {
false,
false,
).Return(400, nil)
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2882,6 +2888,8 @@ func (suite *HandlerSuite) TestDenySITExtensionHandler() {
}
func (suite *HandlerSuite) CreateApprovedSITDurationUpdate() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
suite.Run("Returns 200, creates new SIT extension, and updates SIT days allowance on shipment without an allowance when validations pass", func() {
mtoShipment := factory.BuildMTOShipment(suite.DB(), nil, nil)
@@ -2902,7 +2910,7 @@ func (suite *HandlerSuite) CreateApprovedSITDurationUpdate() {
false,
false,
).Return(400, nil)
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -2987,7 +2995,7 @@ func (suite *HandlerSuite) CreateApprovedSITDurationUpdate() {
false,
false,
).Return(400, nil)
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
@@ -4058,6 +4066,7 @@ func (suite *HandlerSuite) getUpdateShipmentParams(originalShipment models.MTOSh
func (suite *HandlerSuite) TestUpdateShipmentHandler() {
addressUpdater := address.NewAddressUpdater()
addressCreator := address.NewAddressCreator()
+ waf := entitlements.NewWeightAllotmentFetcher()
planner := &routemocks.Planner{}
planner.On("ZipTransitDistance",
@@ -4068,7 +4077,7 @@ func (suite *HandlerSuite) TestUpdateShipmentHandler() {
false,
).Return(400, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
diff --git a/pkg/handlers/ghcapi/orders.go b/pkg/handlers/ghcapi/orders.go
index 21706535e6a..a92eb81dbc3 100644
--- a/pkg/handlers/ghcapi/orders.go
+++ b/pkg/handlers/ghcapi/orders.go
@@ -164,6 +164,7 @@ func (h CounselingUpdateOrderHandler) Handle(
// CounselingUpdateOrderHandler create an order via POST /orders
type CreateOrderHandler struct {
handlers.HandlerConfig
+ services.WeightAllotmentFetcher
}
// Handle ... creates an order as requested by a services counselor
@@ -237,7 +238,12 @@ func (h CreateOrderHandler) Handle(params orderop.CreateOrderParams) middleware.
grade := (internalmessages.OrderPayGrade)(*payload.Grade)
ordersType := (internalmessages.OrdersType)(*payload.OrdersType)
- weightAllotment := models.GetWeightAllotment(grade, ordersType)
+ weightAllotment, err := h.WeightAllotmentFetcher.GetWeightAllotment(appCtx, string(grade), ordersType)
+ if err != nil {
+ err = apperror.NewBadDataError("Weight allotment cannot be verified")
+ appCtx.Logger().Error(err.Error())
+ return orderop.NewCreateOrderUnprocessableEntity(), err
+ }
weight := weightAllotment.TotalWeightSelf
if *payload.HasDependents {
weight = weightAllotment.TotalWeightSelfPlusDependents
diff --git a/pkg/handlers/ghcapi/orders_test.go b/pkg/handlers/ghcapi/orders_test.go
index 9dba706d059..ccbd4ca8aac 100644
--- a/pkg/handlers/ghcapi/orders_test.go
+++ b/pkg/handlers/ghcapi/orders_test.go
@@ -22,6 +22,7 @@ import (
"github.com/transcom/mymove/pkg/models/roles"
routemocks "github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/mocks"
moverouter "github.com/transcom/mymove/pkg/services/move"
@@ -36,6 +37,7 @@ import (
)
func (suite *HandlerSuite) TestCreateOrder() {
+ waf := entitlements.NewWeightAllotmentFetcher()
sm := factory.BuildExtendedServiceMember(suite.AppContextForTest().DB(), nil, nil)
officeUser := factory.BuildOfficeUserWithRoles(suite.AppContextForTest().DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
@@ -84,7 +86,7 @@ func (suite *HandlerSuite) TestCreateOrder() {
fakeS3 := storageTest.NewFakeS3Storage(true)
handlerConfig := suite.HandlerConfig()
handlerConfig.SetFileStorer(fakeS3)
- createHandler := CreateOrderHandler{handlerConfig}
+ createHandler := CreateOrderHandler{handlerConfig, waf}
response := createHandler.Handle(params)
@@ -107,6 +109,8 @@ func (suite *HandlerSuite) TestCreateOrder() {
}
func (suite *HandlerSuite) TestCreateOrderWithOCONUSValues() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
sm := factory.BuildExtendedServiceMember(suite.AppContextForTest().DB(), nil, nil)
officeUser := factory.BuildOfficeUserWithRoles(suite.AppContextForTest().DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
@@ -160,7 +164,7 @@ func (suite *HandlerSuite) TestCreateOrderWithOCONUSValues() {
fakeS3 := storageTest.NewFakeS3Storage(true)
handlerConfig := suite.HandlerConfig()
handlerConfig.SetFileStorer(fakeS3)
- createHandler := CreateOrderHandler{handlerConfig}
+ createHandler := CreateOrderHandler{handlerConfig, waf}
response := createHandler.Handle(params)
@@ -187,7 +191,7 @@ func (suite *HandlerSuite) TestCreateOrderWithOCONUSValues() {
func (suite *HandlerSuite) TestGetOrderHandlerIntegration() {
officeUser := factory.BuildOfficeUserWithRoles(nil, nil, []roles.RoleType{roles.RoleTypeTOO})
-
+ waf := entitlements.NewWeightAllotmentFetcher()
move := factory.BuildMove(suite.DB(), nil, nil)
order := move.Orders
request := httptest.NewRequest("GET", "/orders/{orderID}", nil)
@@ -200,7 +204,7 @@ func (suite *HandlerSuite) TestGetOrderHandlerIntegration() {
handlerConfig := suite.HandlerConfig()
handler := GetOrdersHandler{
handlerConfig,
- orderservice.NewOrderFetcher(),
+ orderservice.NewOrderFetcher(waf),
}
// Validate incoming payload: no body to validate
@@ -235,7 +239,7 @@ func (suite *HandlerSuite) TestGetOrderHandlerIntegration() {
func (suite *HandlerSuite) TestWeightAllowances() {
suite.Run("With E-1 rank and no dependents", func() {
- order := factory.BuildOrder(nil, []factory.Customization{
+ order := factory.BuildOrder(suite.DB(), []factory.Customization{
{
Model: models.Order{
ID: uuid.Must(uuid.NewV4()),
@@ -289,7 +293,7 @@ func (suite *HandlerSuite) TestWeightAllowances() {
})
suite.Run("With E-1 rank and dependents", func() {
- order := factory.BuildOrder(nil, []factory.Customization{
+ order := factory.BuildOrder(suite.DB(), []factory.Customization{
{
Model: models.Order{
ID: uuid.Must(uuid.NewV4()),
diff --git a/pkg/handlers/ghcapi/ppm_shipment_test.go b/pkg/handlers/ghcapi/ppm_shipment_test.go
index d5e358feb4a..bc8093032b5 100644
--- a/pkg/handlers/ghcapi/ppm_shipment_test.go
+++ b/pkg/handlers/ghcapi/ppm_shipment_test.go
@@ -26,7 +26,7 @@ func (suite *HandlerSuite) TestGetPPMSITEstimatedCostHandler() {
var ppmShipment models.PPMShipment
newFakeSITEstimatedCost := models.CentPointer(unit.Cents(25500))
- setupPricerData := func() {
+ suite.PreloadData(func() {
testdatagen.FetchOrMakeGHCDieselFuelPrice(suite.DB(), testdatagen.Assertions{
GHCDieselFuelPrice: models.GHCDieselFuelPrice{
FuelPriceInMillicents: unit.Millicents(281400),
@@ -342,10 +342,9 @@ func (suite *HandlerSuite) TestGetPPMSITEstimatedCostHandler() {
PriceCents: 63,
},
})
- }
+ })
- suite.PreloadData(func() {
- setupPricerData()
+ setupData := func() {
sitLocationDestination := models.SITLocationTypeDestination
entryDate := time.Date(2020, time.March, 15, 0, 0, 0, 0, time.UTC)
mtoShipment := factory.BuildMTOShipment(suite.DB(), []factory.Customization{
@@ -389,7 +388,8 @@ func (suite *HandlerSuite) TestGetPPMSITEstimatedCostHandler() {
mockedPlanner := &routemocks.Planner{}
mockedPlanner.On("ZipTransitDistance", mock.AnythingOfType("*appcontext.appContext"),
"90210", "30813", false, false).Return(2294, nil)
- })
+ }
+ setupData()
setUpGetCostRequestAndParams := func() ppmsitops.GetPPMSITEstimatedCostParams {
endpoint := fmt.Sprintf("/ppm-shipments/%s/sit_location/%s/sit-estimated-cost", ppmShipment.ID.String(), *ppmShipment.SITLocation)
diff --git a/pkg/handlers/ghcapi/queues_test.go b/pkg/handlers/ghcapi/queues_test.go
index d3feef08c8b..8899da4999f 100644
--- a/pkg/handlers/ghcapi/queues_test.go
+++ b/pkg/handlers/ghcapi/queues_test.go
@@ -15,6 +15,7 @@ import (
"github.com/transcom/mymove/pkg/gen/ghcmessages"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/models/roles"
+ "github.com/transcom/mymove/pkg/services/entitlements"
movelocker "github.com/transcom/mymove/pkg/services/lock_move"
"github.com/transcom/mymove/pkg/services/mocks"
movefetcher "github.com/transcom/mymove/pkg/services/move"
@@ -25,6 +26,8 @@ import (
)
func (suite *HandlerSuite) TestGetMoveQueuesHandler() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitActiveOfficeUser(), []roles.RoleType{roles.RoleTypeTOO})
factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitActiveOfficeUser(), []roles.RoleType{roles.RoleTypeTIO})
officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{
@@ -77,7 +80,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandler() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -109,6 +112,8 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandler() {
}
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{
@@ -232,7 +237,7 @@ func (suite *HandlerSuite) TestGetDestinationRequestsQueuesHandler() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetDestinationRequestsQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -253,6 +258,7 @@ func (suite *HandlerSuite) TestGetDestinationRequestsQueuesHandler() {
func (suite *HandlerSuite) TestListPrimeMovesHandler() {
// Default Origin Duty Location GBLOC is KKFA
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
request := httptest.NewRequest("GET", "/queues/listPrimeMoves", nil)
params := queues.ListPrimeMovesParams{
@@ -261,7 +267,7 @@ func (suite *HandlerSuite) TestListPrimeMovesHandler() {
handlerConfig := suite.HandlerConfig()
handler := ListPrimeMovesHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
// Validate incoming payload: no body to validate
@@ -376,6 +382,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesBranchFilter() {
officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{
RoleType: roles.RoleTypeTOO,
})
+ waf := entitlements.NewWeightAllotmentFetcher()
move := models.Move{
Status: models.MoveStatusSUBMITTED,
@@ -421,7 +428,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesBranchFilter() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -447,6 +454,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerStatuses() {
officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{
RoleType: roles.RoleTypeTOO,
})
+ waf := entitlements.NewWeightAllotmentFetcher()
// Default Origin Duty Location GBLOC is KKFA
hhgMove := factory.BuildSubmittedMove(suite.DB(), nil, nil)
@@ -509,7 +517,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerStatuses() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -571,6 +579,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerFilters() {
officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{
RoleType: roles.RoleTypeTOO,
})
+ waf := entitlements.NewWeightAllotmentFetcher()
submittedMove := models.Move{
Status: models.MoveStatusSUBMITTED,
@@ -663,7 +672,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerFilters() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -824,6 +833,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerCustomerInfoFilters() {
},
},
}, nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
dutyLocation2 := factory.BuildDutyLocation(suite.DB(), nil, nil)
@@ -920,7 +930,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerCustomerInfoFilters() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -1056,6 +1066,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerCustomerInfoFilters() {
func (suite *HandlerSuite) TestGetMoveQueuesHandlerUnauthorizedRole() {
officeUser := factory.BuildOfficeUserWithRoles(nil, nil, []roles.RoleType{roles.RoleTypeTIO})
+ waf := entitlements.NewWeightAllotmentFetcher()
request := httptest.NewRequest("GET", "/queues/moves", nil)
request = suite.AuthenticateOfficeRequest(request, officeUser)
@@ -1066,7 +1077,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerUnauthorizedRole() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -1087,6 +1098,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerUnauthorizedUser() {
serviceUser.User.Roles = append(serviceUser.User.Roles, roles.Role{
RoleType: roles.RoleTypeCustomer,
})
+ waf := entitlements.NewWeightAllotmentFetcher()
request := httptest.NewRequest("GET", "/queues/moves", nil)
request = suite.AuthenticateRequest(request, serviceUser)
@@ -1097,7 +1109,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerUnauthorizedUser() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -1118,6 +1130,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerEmptyResults() {
officeUser.User.Roles = append(officeUser.User.Roles, roles.Role{
RoleType: roles.RoleTypeTOO,
})
+ waf := entitlements.NewWeightAllotmentFetcher()
// Create an order with an origin duty location outside of office user GBLOC
excludedMove := factory.BuildMove(suite.DB(), []factory.Customization{
@@ -1149,7 +1162,7 @@ func (suite *HandlerSuite) TestGetMoveQueuesHandlerEmptyResults() {
mockUnlocker := movelocker.NewMoveUnlocker()
handler := GetMovesQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
@@ -1463,6 +1476,7 @@ type servicesCounselingSubtestData struct {
func (suite *HandlerSuite) makeServicesCounselingSubtestData() (subtestData *servicesCounselingSubtestData) {
subtestData = &servicesCounselingSubtestData{}
subtestData.officeUser = factory.BuildOfficeUserWithRoles(suite.DB(), factory.GetTraitActiveOfficeUser(), []roles.RoleType{roles.RoleTypeServicesCounselor})
+ waf := entitlements.NewWeightAllotmentFetcher()
submittedAt := time.Date(2021, 03, 15, 0, 0, 0, 0, time.UTC)
// Default Origin Duty Location GBLOC is KKFA
@@ -1659,7 +1673,7 @@ func (suite *HandlerSuite) makeServicesCounselingSubtestData() (subtestData *ser
mockUnlocker := movelocker.NewMoveUnlocker()
subtestData.handler = GetServicesCounselingQueueHandler{
handlerConfig,
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
mockUnlocker,
officeusercreator.NewOfficeUserFetcherPop(),
}
diff --git a/pkg/handlers/internalapi/api.go b/pkg/handlers/internalapi/api.go
index dfbad6e2ba9..31010c7e3da 100644
--- a/pkg/handlers/internalapi/api.go
+++ b/pkg/handlers/internalapi/api.go
@@ -17,6 +17,7 @@ import (
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
dateservice "github.com/transcom/mymove/pkg/services/calendar"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -57,6 +58,7 @@ func NewInternalAPI(handlerConfig handlers.HandlerConfig) *internalops.MymoveAPI
builder := query.NewQueryBuilder()
fetcher := fetch.NewFetcher(builder)
moveRouter := move.NewMoveRouter()
+ waf := entitlements.NewWeightAllotmentFetcher()
uploadCreator := upload.NewUploadCreator(handlerConfig.FileStorer())
ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{})
ppmCloseoutFetcher := ppmcloseout.NewPPMCloseoutFetcher(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{}, ppmEstimator)
@@ -174,12 +176,11 @@ func NewInternalAPI(handlerConfig handlers.HandlerConfig) *internalops.MymoveAPI
internalAPI.UploadsDeleteUploadHandler = DeleteUploadHandler{handlerConfig, upload.NewUploadInformationFetcher()}
internalAPI.UploadsDeleteUploadsHandler = DeleteUploadsHandler{handlerConfig}
- internalAPI.QueuesShowQueueHandler = ShowQueueHandler{handlerConfig}
internalAPI.OfficeApproveMoveHandler = ApproveMoveHandler{handlerConfig, moveRouter}
internalAPI.OfficeApproveReimbursementHandler = ApproveReimbursementHandler{handlerConfig}
internalAPI.OfficeCancelMoveHandler = CancelMoveHandler{handlerConfig, moveRouter}
- internalAPI.EntitlementsIndexEntitlementsHandler = IndexEntitlementsHandler{handlerConfig}
+ internalAPI.EntitlementsIndexEntitlementsHandler = IndexEntitlementsHandler{handlerConfig, waf}
internalAPI.CalendarShowAvailableMoveDatesHandler = ShowAvailableMoveDatesHandler{handlerConfig}
@@ -235,7 +236,7 @@ func NewInternalAPI(handlerConfig handlers.HandlerConfig) *internalops.MymoveAPI
fetcher,
handlerConfig.DTODPlanner(),
moveRouter,
- move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester()),
+ move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf),
handlerConfig.NotificationSender(),
paymentRequestShipmentRecalculator,
addressUpdater,
diff --git a/pkg/handlers/internalapi/api_test.go b/pkg/handlers/internalapi/api_test.go
index ef45c139cd0..e4c243a6dd2 100644
--- a/pkg/handlers/internalapi/api_test.go
+++ b/pkg/handlers/internalapi/api_test.go
@@ -5,7 +5,9 @@ import (
"github.com/stretchr/testify/suite"
+ "github.com/transcom/mymove/pkg/factory"
"github.com/transcom/mymove/pkg/handlers"
+ "github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/notifications"
storageTest "github.com/transcom/mymove/pkg/storage/test"
"github.com/transcom/mymove/pkg/testingsuite"
@@ -25,6 +27,19 @@ type HandlerSuite struct {
handlers.BaseHandlerTestSuite
}
+func (suite *HandlerSuite) SetupSuite() {
+ suite.PreloadData(func() {
+ factory.FetchOrBuildCountry(suite.DB(), []factory.Customization{
+ {
+ Model: models.Country{
+ Country: "US",
+ CountryName: "UNITED STATES",
+ },
+ },
+ }, nil)
+ })
+}
+
// AfterTest completes tests by trying to close open files
func (suite *HandlerSuite) AfterTest() {
for _, file := range suite.TestFilesToClose() {
diff --git a/pkg/handlers/internalapi/entitlements.go b/pkg/handlers/internalapi/entitlements.go
index 3ae75c18eb4..ed50edbb132 100644
--- a/pkg/handlers/internalapi/entitlements.go
+++ b/pkg/handlers/internalapi/entitlements.go
@@ -8,6 +8,7 @@ import (
"github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services"
)
func payloadForEntitlementModel(e models.WeightAllotment) internalmessages.WeightAllotment {
@@ -28,13 +29,17 @@ func payloadForEntitlementModel(e models.WeightAllotment) internalmessages.Weigh
// IndexEntitlementsHandler indexes entitlements
type IndexEntitlementsHandler struct {
handlers.HandlerConfig
+ services.WeightAllotmentFetcher
}
// Handle is the handler
func (h IndexEntitlementsHandler) Handle(params entitlementop.IndexEntitlementsParams) middleware.Responder {
return h.AuditableAppContextFromRequestWithErrors(params.HTTPRequest,
func(appCtx appcontext.AppContext) (middleware.Responder, error) {
- entitlements := models.AllWeightAllotments()
+ entitlements, err := h.WeightAllotmentFetcher.GetAllWeightAllotments(appCtx)
+ if err != nil {
+ return entitlementop.NewIndexEntitlementsInternalServerError(), nil
+ }
payload := make(map[string]internalmessages.WeightAllotment)
for k, v := range entitlements {
grade := string(k)
diff --git a/pkg/handlers/internalapi/entitlements_test.go b/pkg/handlers/internalapi/entitlements_test.go
index ec6829443c2..0b896da13b9 100644
--- a/pkg/handlers/internalapi/entitlements_test.go
+++ b/pkg/handlers/internalapi/entitlements_test.go
@@ -5,11 +5,13 @@ import (
"github.com/transcom/mymove/pkg/factory"
entitlementop "github.com/transcom/mymove/pkg/gen/internalapi/internaloperations/entitlements"
+ "github.com/transcom/mymove/pkg/services/entitlements"
)
func (suite *HandlerSuite) TestIndexEntitlementsHandlerReturns200() {
// Given: a set of orders, a move, user, servicemember and a PPM
+ waf := entitlements.NewWeightAllotmentFetcher()
ppm := factory.BuildMinimalPPMShipment(suite.DB(), nil, nil)
move := factory.BuildMove(suite.DB(), nil, nil)
mtoShipment := factory.BuildMTOShipmentWithMove(&move, suite.DB(), nil, nil)
@@ -24,7 +26,7 @@ func (suite *HandlerSuite) TestIndexEntitlementsHandlerReturns200() {
}
// And: index entitlements endpoint is hit
- handler := IndexEntitlementsHandler{suite.HandlerConfig()}
+ handler := IndexEntitlementsHandler{suite.HandlerConfig(), waf}
response := handler.Handle(params)
// Then: expect a 200 status code
diff --git a/pkg/handlers/internalapi/move_queue_items.go b/pkg/handlers/internalapi/move_queue_items.go
deleted file mode 100644
index 071ae2fba79..00000000000
--- a/pkg/handlers/internalapi/move_queue_items.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package internalapi
-
-import (
- "sort"
- "strings"
- "time"
-
- "github.com/go-openapi/runtime/middleware"
- "github.com/gofrs/uuid"
- "go.uber.org/zap"
-
- "github.com/transcom/mymove/pkg/appcontext"
- "github.com/transcom/mymove/pkg/apperror"
- queueop "github.com/transcom/mymove/pkg/gen/internalapi/internaloperations/queues"
- "github.com/transcom/mymove/pkg/gen/internalmessages"
- "github.com/transcom/mymove/pkg/handlers"
- "github.com/transcom/mymove/pkg/models"
-)
-
-func payloadForMoveQueueItem(MoveQueueItem models.MoveQueueItem) *internalmessages.MoveQueueItem {
- MoveQueueItemPayload := internalmessages.MoveQueueItem{
- ID: handlers.FmtUUID(MoveQueueItem.ID),
- CreatedAt: handlers.FmtDateTime(MoveQueueItem.CreatedAt),
- Edipi: models.StringPointer(MoveQueueItem.Edipi),
- Grade: MoveQueueItem.Grade,
- CustomerName: models.StringPointer(MoveQueueItem.CustomerName),
- Locator: models.StringPointer(MoveQueueItem.Locator),
- Status: models.StringPointer(MoveQueueItem.Status),
- PpmStatus: handlers.FmtStringPtr(MoveQueueItem.PpmStatus),
- OrdersType: MoveQueueItem.OrdersType,
- MoveDate: handlers.FmtDatePtr(MoveQueueItem.MoveDate),
- SubmittedDate: handlers.FmtDateTimePtr(MoveQueueItem.SubmittedDate),
- LastModifiedDate: handlers.FmtDateTime(MoveQueueItem.LastModifiedDate),
- OriginDutyLocationName: models.StringPointer(MoveQueueItem.OriginDutyLocationName),
- DestinationDutyLocationName: models.StringPointer(MoveQueueItem.DestinationDutyLocationName),
- PmSurveyConductedDate: handlers.FmtDateTimePtr(MoveQueueItem.PmSurveyConductedDate),
- OriginGbloc: handlers.FmtStringPtr(MoveQueueItem.OriginGBLOC),
- DestinationGbloc: handlers.FmtStringPtr(MoveQueueItem.DestinationGBLOC),
- DeliveredDate: handlers.FmtDateTimePtr(MoveQueueItem.DeliveredDate),
- InvoiceApprovedDate: handlers.FmtDateTimePtr(MoveQueueItem.InvoiceApprovedDate),
- WeightAllotment: payloadForWeightAllotmentModel(models.GetWeightAllotment(*MoveQueueItem.Grade, *MoveQueueItem.OrdersType)),
- BranchOfService: handlers.FmtString(MoveQueueItem.BranchOfService),
- ActualMoveDate: handlers.FmtDatePtr(MoveQueueItem.ActualMoveDate),
- OriginalMoveDate: handlers.FmtDatePtr(MoveQueueItem.OriginalMoveDate),
- }
- return &MoveQueueItemPayload
-}
-
-// ShowQueueHandler returns a list of all MoveQueueItems in the moves queue
-type ShowQueueHandler struct {
- handlers.HandlerConfig
-}
-
-// JSONDate is a time type
-type JSONDate time.Time
-
-// UnmarshalJSON Dates without timestamps need custom unmarshalling
-func (j *JSONDate) UnmarshalJSON(b []byte) error {
- s := strings.Trim(string(b), "\"")
- if s == "null" {
- return nil
- }
- t, err := time.Parse("2006-01-02", s)
- if err != nil {
- return err
- }
- *j = JSONDate(t)
- return nil
-}
-
-// QueueSitData is SIT data in a queue
-type QueueSitData struct {
- ID uuid.UUID `json:"id"`
- Status string `json:"status"`
- ActualStartDate JSONDate `json:"actual_start_date"`
- OutDate JSONDate `json:"out_date"`
- Location string `json:"location"`
-}
-
-// MoveQueueItems is a set of move queue items
-// Implementation of a type and methods in order to use sort.Interface directly.
-// This allows us to call sortQueueItemsByLastModifiedDate in the ShowQueueHandler which will
-// sort the slice by the LastModfiedDate. Doing it this way allows us to avoid having reflect called
-// which should act to speed the sort up.
-type MoveQueueItems []models.MoveQueueItem
-
-func (mqi MoveQueueItems) Less(i, j int) bool {
- return mqi[i].LastModifiedDate.Before(mqi[j].LastModifiedDate)
-}
-func (mqi MoveQueueItems) Len() int { return len(mqi) }
-func (mqi MoveQueueItems) Swap(i, j int) { mqi[i], mqi[j] = mqi[j], mqi[i] }
-
-func sortQueueItemsByLastModifiedDate(moveQueueItems []models.MoveQueueItem) {
- sort.Sort(MoveQueueItems(moveQueueItems))
-}
-
-// Handle retrieves a list of all MoveQueueItems in the system in the moves queue
-func (h ShowQueueHandler) Handle(params queueop.ShowQueueParams) middleware.Responder {
- return h.AuditableAppContextFromRequestWithErrors(params.HTTPRequest,
- func(appCtx appcontext.AppContext) (middleware.Responder, error) {
-
- if !appCtx.Session().IsOfficeUser() {
- badUserErr := apperror.NewSessionError("User is not an Office user")
- return queueop.NewShowQueueForbidden(), badUserErr
- }
-
- lifecycleState := params.QueueType
-
- MoveQueueItems, err := models.GetMoveQueueItems(appCtx.DB(), lifecycleState)
- if err != nil {
- appCtx.Logger().Error("Loading Queue", zap.String("State", lifecycleState), zap.Error(err))
- return handlers.ResponseForError(appCtx.Logger(), err), err
- }
-
- // Sorting the slice by LastModifiedDate so that the API results follow suit.
- sortQueueItemsByLastModifiedDate(MoveQueueItems)
-
- MoveQueueItemPayloads := make([]*internalmessages.MoveQueueItem, len(MoveQueueItems))
- for i, MoveQueueItem := range MoveQueueItems {
- MoveQueueItemPayload := payloadForMoveQueueItem(MoveQueueItem)
- MoveQueueItemPayloads[i] = MoveQueueItemPayload
- }
- return queueop.NewShowQueueOK().WithPayload(MoveQueueItemPayloads), nil
- })
-}
diff --git a/pkg/handlers/internalapi/move_queue_items_test.go b/pkg/handlers/internalapi/move_queue_items_test.go
deleted file mode 100644
index bc95161d5d0..00000000000
--- a/pkg/handlers/internalapi/move_queue_items_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package internalapi
-
-import (
- "net/http/httptest"
-
- "github.com/transcom/mymove/pkg/factory"
- queueop "github.com/transcom/mymove/pkg/gen/internalapi/internaloperations/queues"
- "github.com/transcom/mymove/pkg/models/roles"
-)
-
-var statusToQueueMap = map[string]string{
- "SUBMITTED": "new",
- "APPROVED": "ppm_approved",
- "PAYMENT_REQUESTED": "ppm_payment_requested",
- "COMPLETED": "ppm_completed",
-}
-
-func (suite *HandlerSuite) TestShowQueueHandlerForbidden() {
- for _, queueType := range statusToQueueMap {
-
- // Given: A non-office user
- user := factory.BuildServiceMember(suite.DB(), nil, nil)
-
- // And: the context contains the auth values
- path := "/queues/" + queueType
- req := httptest.NewRequest("GET", path, nil)
- req = suite.AuthenticateRequest(req, user)
-
- params := queueop.ShowQueueParams{
- HTTPRequest: req,
- QueueType: queueType,
- }
-
- // And: show Queue is queried
- showHandler := ShowQueueHandler{suite.HandlerConfig()}
- showResponse := showHandler.Handle(params)
-
- // Then: Expect a 403 status code
- suite.Assertions.IsType(&queueop.ShowQueueForbidden{}, showResponse)
- }
-}
-
-func (suite *HandlerSuite) TestShowQueueHandlerNotFound() {
-
- // Given: An office user
- officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
-
- // And: the context contains the auth values
- queueType := "queue_not_found"
- path := "/queues/" + queueType
- req := httptest.NewRequest("GET", path, nil)
- req = suite.AuthenticateOfficeRequest(req, officeUser)
-
- params := queueop.ShowQueueParams{
- HTTPRequest: req,
- QueueType: queueType,
- }
- // And: show Queue is queried
- showHandler := ShowQueueHandler{suite.HandlerConfig()}
- showResponse := showHandler.Handle(params)
-
- // Then: Expect a 404 status code
- suite.CheckResponseNotFound(showResponse)
-}
diff --git a/pkg/handlers/internalapi/mto_shipment_test.go b/pkg/handlers/internalapi/mto_shipment_test.go
index 3d971cc6a38..70636b3c2fc 100644
--- a/pkg/handlers/internalapi/mto_shipment_test.go
+++ b/pkg/handlers/internalapi/mto_shipment_test.go
@@ -22,6 +22,7 @@ import (
"github.com/transcom/mymove/pkg/services"
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -736,6 +737,7 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentHandler() {
testMTOShipmentObjects := suite.setUpMTOShipmentObjects()
planner := &routemocks.Planner{}
+ waf := entitlements.NewWeightAllotmentFetcher()
planner.On("TransitDistance",
mock.AnythingOfType("*appcontext.appContext"),
@@ -743,7 +745,7 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentHandler() {
mock.Anything,
).Return(400, nil)
- moveWeights := moverouter.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moverouter.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
diff --git a/pkg/handlers/internalapi/orders.go b/pkg/handlers/internalapi/orders.go
index 4e20908ae2d..729ad0e03ff 100644
--- a/pkg/handlers/internalapi/orders.go
+++ b/pkg/handlers/internalapi/orders.go
@@ -19,6 +19,7 @@ import (
"github.com/transcom/mymove/pkg/handlers/internalapi/internal/payloads"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/storage"
"github.com/transcom/mymove/pkg/uploader"
)
@@ -195,9 +196,18 @@ func (h CreateOrdersHandler) Handle(params ordersop.CreateOrdersParams) middlewa
grade := payload.Grade
+ if payload.OrdersType == nil {
+ errMsg := "missing required field: OrdersType"
+ return handlers.ResponseForError(appCtx.Logger(), errors.New(errMsg)), apperror.NewBadDataError("missing required field: OrdersType")
+ }
+
// Calculate the entitlement for the order
ordersType := payload.OrdersType
- weightAllotment := models.GetWeightAllotment(*grade, *ordersType)
+ waf := entitlements.NewWeightAllotmentFetcher()
+ weightAllotment, err := waf.GetWeightAllotment(appCtx, string(*grade), *ordersType)
+ if err != nil {
+ return handlers.ResponseForError(appCtx.Logger(), err), err
+ }
weight := weightAllotment.TotalWeightSelf
if *payload.HasDependents {
weight = weightAllotment.TotalWeightSelfPlusDependents
@@ -247,11 +257,6 @@ func (h CreateOrdersHandler) Handle(params ordersop.CreateOrdersParams) middlewa
deptIndicator = &converted
}
- if payload.OrdersType == nil {
- errMsg := "missing required field: OrdersType"
- return handlers.ResponseForError(appCtx.Logger(), errors.New(errMsg)), apperror.NewBadDataError("missing required field: OrdersType")
- }
-
contractor, err := models.FetchGHCPrimeContractor(appCtx.DB())
if err != nil {
return handlers.ResponseForError(appCtx.Logger(), err), err
@@ -442,7 +447,11 @@ func (h UpdateOrdersHandler) Handle(params ordersop.UpdateOrdersParams) middlewa
// Check if the grade or dependents are receiving an update
if hasEntitlementChanged(order, payload.OrdersType, payload.Grade, payload.DependentsUnderTwelve, payload.DependentsTwelveAndOver, payload.AccompaniedTour) {
- weightAllotment := models.GetWeightAllotment(*payload.Grade, *payload.OrdersType)
+ waf := entitlements.NewWeightAllotmentFetcher()
+ weightAllotment, err := waf.GetWeightAllotment(appCtx, string(*payload.Grade), *payload.OrdersType)
+ if err != nil {
+ return handlers.ResponseForError(appCtx.Logger(), err), err
+ }
weight := weightAllotment.TotalWeightSelf
if *payload.HasDependents {
weight = weightAllotment.TotalWeightSelfPlusDependents
diff --git a/pkg/handlers/internalapi/orders_test.go b/pkg/handlers/internalapi/orders_test.go
index 59df8daf475..bf1b4a4303c 100644
--- a/pkg/handlers/internalapi/orders_test.go
+++ b/pkg/handlers/internalapi/orders_test.go
@@ -17,6 +17,7 @@ import (
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/mocks"
"github.com/transcom/mymove/pkg/services/move"
orderservice "github.com/transcom/mymove/pkg/services/order"
@@ -25,16 +26,6 @@ import (
)
func (suite *HandlerSuite) TestCreateOrder() {
- suite.PreloadData(func() {
- factory.FetchOrBuildCountry(suite.DB(), []factory.Customization{
- {
- Model: models.Country{
- Country: "US",
- CountryName: "UNITED STATES",
- },
- },
- }, nil)
- })
sm := factory.BuildExtendedServiceMember(suite.DB(), nil, nil)
suite.Run("can create conus and oconus orders", func() {
testCases := []struct {
@@ -93,6 +84,7 @@ func (suite *HandlerSuite) TestCreateOrder() {
DepartmentIndicator: internalmessages.NewDeptIndicator(deptIndicator),
Grade: models.ServiceMemberGradeE1.Pointer(),
}
+
if tc.isOconus {
payload.AccompaniedTour = models.BoolPointer(true)
payload.DependentsTwelveAndOver = models.Int64Pointer(5)
@@ -584,7 +576,7 @@ func (suite *HandlerSuite) TestUploadAmendedOrdersHandlerIntegration() {
}
func (suite *HandlerSuite) TestUpdateOrdersHandler() {
-
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("Can update CONUS and OCONUS orders", func() {
testCases := []struct {
isOconus bool
@@ -689,13 +681,15 @@ func (suite *HandlerSuite) TestUpdateOrdersHandler() {
suite.NoError(err)
suite.Equal(payload.Grade, updatedOrder.Grade)
suite.Equal(*okResponse.Payload.AuthorizedWeight, int64(7000)) // E4 authorized weight is 7000, make sure we return that in the response
- expectedUpdatedOrderWeightAllotment := models.GetWeightAllotment(*updatedOrder.Grade, updatedOrder.OrdersType)
+ expectedUpdatedOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*updatedOrder.Grade), updatedOrder.OrdersType)
+ suite.NoError(err)
expectedUpdatedOrderAuthorizedWeight := expectedUpdatedOrderWeightAllotment.TotalWeightSelf
if *payload.HasDependents {
expectedUpdatedOrderAuthorizedWeight = expectedUpdatedOrderWeightAllotment.TotalWeightSelfPlusDependents
}
- expectedOriginalOrderWeightAllotment := models.GetWeightAllotment(*order.Grade, updatedOrder.OrdersType)
+ expectedOriginalOrderWeightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*order.Grade), updatedOrder.OrdersType)
+ suite.NoError(err)
expectedOriginalOrderAuthorizedWeight := expectedOriginalOrderWeightAllotment.TotalWeightSelf
if *payload.HasDependents {
expectedUpdatedOrderAuthorizedWeight = expectedOriginalOrderWeightAllotment.TotalWeightSelfPlusDependents
diff --git a/pkg/handlers/internalapi/ppm_shipment_test.go b/pkg/handlers/internalapi/ppm_shipment_test.go
index d01813b5ef8..b9e20809025 100644
--- a/pkg/handlers/internalapi/ppm_shipment_test.go
+++ b/pkg/handlers/internalapi/ppm_shipment_test.go
@@ -798,7 +798,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio
var shipmentNeedsCloseout models.PPMShipment
var needsCloseoutSM models.ServiceMember
- suite.PreloadData(func() {
+ setupPPMData := func() {
shipmentNeedsResubmitted = factory.BuildPPMShipmentThatNeedsToBeResubmitted(suite.DB(), userUploader, nil)
shipmentNeedsResubmitted.SubmittedAt = &submissionTime
suite.NoError(suite.DB().Save(&shipmentNeedsResubmitted))
@@ -806,7 +806,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio
shipmentNeedsCloseout = factory.BuildPPMShipmentThatNeedsCloseout(suite.DB(), nil, nil)
needsCloseoutSM = shipmentNeedsCloseout.Shipment.MoveTaskOrder.Orders.ServiceMember
- })
+ }
setUpParamsAndHandler := func(ppmShipment models.PPMShipment, serviceMember models.ServiceMember, payload *internalmessages.SavePPMShipmentSignedCertification) (ppmops.ResubmitPPMShipmentDocumentationParams, ResubmitPPMShipmentDocumentationHandler) {
endpoint := fmt.Sprintf(
@@ -840,6 +840,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio
}
suite.Run("Returns an error if the PPM shipment is not found", func() {
+ setupPPMData()
shipmentWithUnknownID := models.PPMShipment{
ID: uuid.Must(uuid.NewV4()),
SignedCertification: &models.SignedCertification{
@@ -863,6 +864,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio
})
suite.Run("Returns an error if the signed certification is not found", func() {
+ setupPPMData()
shipmentWithUnknownSignedCert := models.PPMShipment{
ID: shipmentNeedsResubmitted.ID,
SignedCertification: &models.SignedCertification{
@@ -886,6 +888,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio
})
suite.Run("Returns an error if the PPM shipment is not in the right status", func() {
+ setupPPMData()
params, handler := setUpParamsAndHandler(shipmentNeedsCloseout, needsCloseoutSM, &internalmessages.SavePPMShipmentSignedCertification{
CertificationText: handlers.FmtString("certification text"),
Signature: handlers.FmtString("signature"),
@@ -909,6 +912,7 @@ func (suite *HandlerSuite) TestResubmitPPMShipmentDocumentationHandlerIntegratio
})
suite.Run("Can successfully resubmit a PPM shipment for close out", func() {
+ setupPPMData()
newCertText := "new certification text"
newSignature := "new signature"
newSignDate := time.Now().AddDate(0, 0, 1)
diff --git a/pkg/handlers/internalapi/weight_allotment.go b/pkg/handlers/internalapi/weight_allotment.go
deleted file mode 100644
index 90e2058c53f..00000000000
--- a/pkg/handlers/internalapi/weight_allotment.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package internalapi
-
-import (
- "github.com/transcom/mymove/pkg/gen/internalmessages"
- "github.com/transcom/mymove/pkg/handlers"
- "github.com/transcom/mymove/pkg/models"
-)
-
-func payloadForWeightAllotmentModel(allotment models.WeightAllotment) *internalmessages.WeightAllotment {
- return &internalmessages.WeightAllotment{
- ProGearWeight: handlers.FmtInt64(int64(allotment.ProGearWeight)),
- ProGearWeightSpouse: handlers.FmtInt64(int64(allotment.ProGearWeightSpouse)),
- TotalWeightSelf: handlers.FmtInt64(int64(allotment.TotalWeightSelf)),
- TotalWeightSelfPlusDependents: handlers.FmtInt64(int64(allotment.TotalWeightSelfPlusDependents)),
- }
-}
diff --git a/pkg/handlers/pptasapi/api.go b/pkg/handlers/pptasapi/api.go
index 7278f68c0dd..b3e6a418831 100644
--- a/pkg/handlers/pptasapi/api.go
+++ b/pkg/handlers/pptasapi/api.go
@@ -9,6 +9,7 @@ import (
pptasops "github.com/transcom/mymove/pkg/gen/pptasapi/pptasoperations"
"github.com/transcom/mymove/pkg/handlers"
paymentrequesthelper "github.com/transcom/mymove/pkg/payment_request"
+ "github.com/transcom/mymove/pkg/services/entitlements"
lineofaccounting "github.com/transcom/mymove/pkg/services/line_of_accounting"
"github.com/transcom/mymove/pkg/services/move"
"github.com/transcom/mymove/pkg/services/ppmshipment"
@@ -18,6 +19,7 @@ import (
func NewPPTASAPI(handlerConfig handlers.HandlerConfig) *pptasops.MymoveAPI {
pptasSpec, err := loads.Analyzed(pptasapi.SwaggerJSON, "")
+ waf := entitlements.NewWeightAllotmentFetcher()
if err != nil {
log.Fatalln(err)
}
@@ -31,7 +33,7 @@ func NewPPTASAPI(handlerConfig handlers.HandlerConfig) *pptasops.MymoveAPI {
pptasAPI.MovesPptasReportsHandler = PPTASReportsHandler{
HandlerConfig: handlerConfig,
- PPTASReportListFetcher: report.NewPPTASReportListFetcher(ppmEstimator, moveFetcher, tacFetcher, loaFetcher),
+ PPTASReportListFetcher: report.NewPPTASReportListFetcher(ppmEstimator, moveFetcher, tacFetcher, loaFetcher, waf),
}
return pptasAPI
diff --git a/pkg/handlers/primeapi/api.go b/pkg/handlers/primeapi/api.go
index a96b47ac5f2..4eab1923c9f 100644
--- a/pkg/handlers/primeapi/api.go
+++ b/pkg/handlers/primeapi/api.go
@@ -11,6 +11,7 @@ import (
paperwork "github.com/transcom/mymove/pkg/paperwork"
paymentrequesthelper "github.com/transcom/mymove/pkg/payment_request"
"github.com/transcom/mymove/pkg/services/address"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/move"
@@ -41,13 +42,15 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP
if err != nil {
log.Fatalln(err)
}
+ waf := entitlements.NewWeightAllotmentFetcher()
+
primeAPI := primeoperations.NewMymoveAPI(primeSpec)
queryBuilder := query.NewQueryBuilder()
moveRouter := move.NewMoveRouter()
addressCreator := address.NewAddressCreator()
portLocationFetcher := portlocation.NewPortLocationFetcher()
shipmentFetcher := mtoshipment.NewMTOShipmentFetcher()
- moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
uploadCreator := upload.NewUploadCreator(handlerConfig.FileStorer())
ppmEstimator := ppmshipment.NewEstimatePPM(handlerConfig.DTODPlanner(), &paymentrequesthelper.RequestPaymentHelper{})
serviceItemUpdater := mtoserviceitem.NewMTOServiceItemUpdater(handlerConfig.HHGPlanner(), queryBuilder, moveRouter, shipmentFetcher, addressCreator, portLocationFetcher, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer())
@@ -79,12 +82,12 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP
primeAPI.MoveTaskOrderListMovesHandler = ListMovesHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
primeAPI.MoveTaskOrderGetMoveTaskOrderHandler = GetMoveTaskOrderHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
primeAPI.MoveTaskOrderCreateExcessWeightRecordHandler = CreateExcessWeightRecordHandler{
@@ -187,7 +190,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primeoperations.MymoveAP
primeAPI.MoveTaskOrderDownloadMoveOrderHandler = DownloadMoveOrderHandler{
handlerConfig,
move.NewMoveSearcher(),
- order.NewOrderFetcher(),
+ order.NewOrderFetcher(waf),
primeDownloadMoveUploadPDFGenerator,
}
diff --git a/pkg/handlers/primeapi/move_task_order_test.go b/pkg/handlers/primeapi/move_task_order_test.go
index b659b9386d9..f1005d9f41e 100644
--- a/pkg/handlers/primeapi/move_task_order_test.go
+++ b/pkg/handlers/primeapi/move_task_order_test.go
@@ -21,6 +21,7 @@ import (
"github.com/transcom/mymove/pkg/models"
routemocks "github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/mocks"
@@ -36,6 +37,8 @@ import (
)
func (suite *HandlerSuite) TestListMovesHandler() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
suite.Run("Test returns updated with no amendments count", func() {
now := time.Now()
lastFetch := now.Add(-time.Second)
@@ -59,7 +62,7 @@ func (suite *HandlerSuite) TestListMovesHandler() {
// Validate incoming payload: no body to validate
// make the request
- handler := ListMovesHandler{HandlerConfig: handlerConfig, MoveTaskOrderFetcher: movetaskorder.NewMoveTaskOrderFetcher()}
+ handler := ListMovesHandler{HandlerConfig: handlerConfig, MoveTaskOrderFetcher: movetaskorder.NewMoveTaskOrderFetcher(waf)}
response := handler.Handle(params)
suite.IsNotErrResponse(response)
@@ -131,7 +134,7 @@ func (suite *HandlerSuite) TestListMovesHandler() {
// Validate incoming payload: no body to validate
// make the request
- handler := ListMovesHandler{HandlerConfig: handlerConfig, MoveTaskOrderFetcher: movetaskorder.NewMoveTaskOrderFetcher()}
+ handler := ListMovesHandler{HandlerConfig: handlerConfig, MoveTaskOrderFetcher: movetaskorder.NewMoveTaskOrderFetcher(waf)}
response := handler.Handle(params)
suite.IsNotErrResponse(response)
@@ -150,6 +153,7 @@ func (suite *HandlerSuite) TestListMovesHandler() {
func (suite *HandlerSuite) TestGetMoveTaskOrder() {
request := httptest.NewRequest("GET", "/move-task-orders/{moveTaskOrderID}", nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
verifyAddressFields := func(address *models.Address, payload *primemessages.Address) {
suite.Equal(address.ID.String(), payload.ID.String())
@@ -169,7 +173,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success with Prime-available move by ID", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -200,7 +204,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success with Prime-available move by Locator", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -230,7 +234,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success returns reweighs on shipments if they exist", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -284,7 +288,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns sit extensions on shipments if they exist", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -342,7 +346,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - filters shipments handled by an external vendor", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -397,7 +401,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns shipment with attached PpmShipment", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
ppmShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{
@@ -433,7 +437,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
// This tests fields that aren't other structs and Addresses
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
destinationAddress := factory.BuildAddress(suite.DB(), nil, nil)
@@ -548,7 +552,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns all the fields associated with StorageFacility within MtoShipments", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -604,7 +608,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns all the fields associated with Agents within MtoShipments", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -655,7 +659,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all base fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
now := time.Now()
aWeekAgo := now.AddDate(0, 0, -7)
@@ -707,7 +711,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all Order fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
currentAddress := factory.BuildAddress(suite.DB(), nil, nil)
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{
@@ -794,10 +798,10 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.NotNil(ordersPayload.OriginDutyLocation.ETag)
})
- suite.Run("Success - return all PaymentRequests fields assoicated with the getMoveTaskOrder", func() {
+ suite.Run("Success - return all PaymentRequests fields associated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -938,10 +942,20 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.NoError(movePayload.Validate(strfmt.Default))
suite.Len(movePayload.PaymentRequests, 2)
- paymentRequestPayload := movePayload.PaymentRequests[0]
+ var paymentRequestPayload *primemessages.PaymentRequest
+ // Correctly grab the payment request by id
+ for _, pr := range movePayload.PaymentRequests {
+ if pr.ID.String() == paymentRequest.ID.String() {
+ paymentRequestPayload = pr
+ break
+ }
+ }
+ suite.NotNil(paymentRequestPayload)
suite.Equal(paymentRequest.ID.String(), paymentRequestPayload.ID.String())
suite.Equal(successMove.ID.String(), paymentRequestPayload.MoveTaskOrderID.String())
suite.Equal(paymentRequest.IsFinal, *paymentRequestPayload.IsFinal)
+ suite.NotNil(paymentRequest.RejectionReason)
+ suite.NotNil(paymentRequestPayload.RejectionReason)
suite.Equal(*paymentRequest.RejectionReason, *paymentRequestPayload.RejectionReason)
suite.Equal(paymentRequest.Status.String(), string(paymentRequestPayload.Status))
suite.Equal(paymentRequest.PaymentRequestNumber, paymentRequestPayload.PaymentRequestNumber)
@@ -989,7 +1003,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemBasic fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1068,7 +1082,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemOriginSIT fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1182,7 +1196,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemDestSIT fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1307,7 +1321,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemShuttle fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1393,7 +1407,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemDomesticCrating fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1521,7 +1535,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Failure 'Not Found' for non-available move", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
failureMove := factory.BuildMove(suite.DB(), nil, nil) // default is not available to Prime
params := movetaskorderops.GetMoveTaskOrderParams{
diff --git a/pkg/handlers/primeapi/mto_shipment_test.go b/pkg/handlers/primeapi/mto_shipment_test.go
index 917e10cdfc6..7e5539b18fd 100644
--- a/pkg/handlers/primeapi/mto_shipment_test.go
+++ b/pkg/handlers/primeapi/mto_shipment_test.go
@@ -22,6 +22,7 @@ import (
routemocks "github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services"
"github.com/transcom/mymove/pkg/services/address"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/mocks"
@@ -199,6 +200,8 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentStatusHandler() {
builder := query.NewQueryBuilder()
fetcher := fetch.NewFetcher(builder)
planner := &routemocks.Planner{}
+ waf := entitlements.NewWeightAllotmentFetcher()
+
planner.On("ZipTransitDistance",
mock.AnythingOfType("*appcontext.appContext"),
mock.Anything,
@@ -209,7 +212,7 @@ func (suite *HandlerSuite) TestUpdateMTOShipmentStatusHandler() {
moveRouter := moveservices.NewMoveRouter()
addressUpdater := address.NewAddressUpdater()
addressCreator := address.NewAddressCreator()
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
// Get shipment payment request recalculator service
creator := paymentrequest.NewPaymentRequestCreator(planner, ghcrateengine.NewServiceItemPricer())
statusUpdater := paymentrequest.NewPaymentRequestStatusUpdater(query.NewQueryBuilder())
diff --git a/pkg/handlers/primeapi/payloads/model_to_payload.go b/pkg/handlers/primeapi/payloads/model_to_payload.go
index 7fb7aaf2447..e4b759cd0e5 100644
--- a/pkg/handlers/primeapi/payloads/model_to_payload.go
+++ b/pkg/handlers/primeapi/payloads/model_to_payload.go
@@ -182,9 +182,6 @@ func Order(order *models.Order) *primemessages.Order {
}
destinationDutyLocation := DutyLocation(&order.NewDutyLocation)
originDutyLocation := DutyLocation(order.OriginDutyLocation)
- if order.Grade != nil && order.Entitlement != nil {
- order.Entitlement.SetWeightAllotment(string(*order.Grade), order.OrdersType)
- }
var grade string
if order.Grade != nil {
diff --git a/pkg/handlers/primeapi/payloads/model_to_payload_test.go b/pkg/handlers/primeapi/payloads/model_to_payload_test.go
index dc0707e5b06..a643a414699 100644
--- a/pkg/handlers/primeapi/payloads/model_to_payload_test.go
+++ b/pkg/handlers/primeapi/payloads/model_to_payload_test.go
@@ -13,6 +13,7 @@ import (
"github.com/transcom/mymove/pkg/gen/primemessages"
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/storage/test"
"github.com/transcom/mymove/pkg/unit"
)
@@ -279,6 +280,7 @@ func (suite *PayloadsSuite) TestSitExtension() {
}
func (suite *PayloadsSuite) TestEntitlement() {
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("Success - Returns the entitlement payload with only required fields", func() {
entitlement := models.Entitlement{
@@ -340,8 +342,9 @@ func (suite *PayloadsSuite) TestEntitlement() {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
-
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
suite.Equal(strfmt.UUID(entitlement.ID.String()), payload.ID)
@@ -381,7 +384,9 @@ func (suite *PayloadsSuite) TestEntitlement() {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
diff --git a/pkg/handlers/primeapiv2/api.go b/pkg/handlers/primeapiv2/api.go
index 72468b5a5f4..44e8ca916ef 100644
--- a/pkg/handlers/primeapiv2/api.go
+++ b/pkg/handlers/primeapiv2/api.go
@@ -11,6 +11,7 @@ import (
paymentrequesthelper "github.com/transcom/mymove/pkg/payment_request"
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -31,6 +32,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev2operations.Mymove
fetcher := fetch.NewFetcher(builder)
queryBuilder := query.NewQueryBuilder()
moveRouter := move.NewMoveRouter()
+ waf := entitlements.NewWeightAllotmentFetcher()
primeSpec, err := loads.Analyzed(primev2api.SwaggerJSON, "")
if err != nil {
@@ -44,7 +46,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev2operations.Mymove
primeAPIV2.MoveTaskOrderGetMoveTaskOrderHandler = GetMoveTaskOrderHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
signedCertificationCreator := signedcertification.NewSignedCertificationCreator()
@@ -90,7 +92,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev2operations.Mymove
paymentrequest.NewPaymentRequestStatusUpdater(queryBuilder),
)
paymentRequestShipmentRecalculator := paymentrequest.NewPaymentRequestShipmentRecalculator(paymentRequestRecalculator)
- moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
addressUpdater := address.NewAddressUpdater()
mtoShipmentUpdater := mtoshipment.NewPrimeMTOShipmentUpdater(
builder,
diff --git a/pkg/handlers/primeapiv2/move_task_order_test.go b/pkg/handlers/primeapiv2/move_task_order_test.go
index 9636b898359..9d736c5b8d5 100644
--- a/pkg/handlers/primeapiv2/move_task_order_test.go
+++ b/pkg/handlers/primeapiv2/move_task_order_test.go
@@ -13,6 +13,7 @@ import (
"github.com/transcom/mymove/pkg/gen/primev2messages"
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services/entitlements"
movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order"
"github.com/transcom/mymove/pkg/testdatagen"
"github.com/transcom/mymove/pkg/unit"
@@ -20,6 +21,7 @@ import (
func (suite *HandlerSuite) TestGetMoveTaskOrder() {
request := httptest.NewRequest("GET", "/move-task-orders/{moveTaskOrderID}", nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
verifyAddressFields := func(address *models.Address, payload *primev2messages.Address) {
suite.Equal(address.ID.String(), payload.ID.String())
@@ -39,7 +41,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success with Prime-available move by ID", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -70,7 +72,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success with Prime-available move by Locator", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -100,7 +102,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success returns reweighs on shipments if they exist", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -154,7 +156,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns sit extensions on shipments if they exist", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -212,7 +214,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - filters shipments handled by an external vendor", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -267,7 +269,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns shipment with attached PpmShipment", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
move := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
ppmShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{
@@ -303,7 +305,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
// This tests fields that aren't other structs and Addresses
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
destinationAddress := factory.BuildAddress(suite.DB(), nil, nil)
@@ -418,7 +420,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns all the fields associated with StorageFacility within MtoShipments", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -474,7 +476,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - returns all the fields associated with Agents within MtoShipments", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
params := movetaskorderops.GetMoveTaskOrderParams{
@@ -525,7 +527,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all base fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
now := time.Now()
aWeekAgo := now.AddDate(0, 0, -7)
@@ -578,7 +580,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all Order fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
currentAddress := factory.BuildAddress(suite.DB(), nil, nil)
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{
@@ -673,7 +675,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all PaymentRequests fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -862,7 +864,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemBasic fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -941,7 +943,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemOriginSIT fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1055,7 +1057,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemDestSIT fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1180,7 +1182,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemShuttle fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1266,7 +1268,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Success - return all MTOServiceItemDomesticCrating fields assoicated with the getMoveTaskOrder", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1394,7 +1396,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Failure 'Not Found' for non-available move", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
failureMove := factory.BuildMove(suite.DB(), nil, nil) // default is not available to Prime
params := movetaskorderops.GetMoveTaskOrderParams{
diff --git a/pkg/handlers/primeapiv2/payloads/model_to_payload.go b/pkg/handlers/primeapiv2/payloads/model_to_payload.go
index 8fad91b99ac..7f51632462e 100644
--- a/pkg/handlers/primeapiv2/payloads/model_to_payload.go
+++ b/pkg/handlers/primeapiv2/payloads/model_to_payload.go
@@ -110,9 +110,6 @@ func Order(order *models.Order) *primev2messages.Order {
}
destinationDutyLocation := DutyLocation(&order.NewDutyLocation)
originDutyLocation := DutyLocation(order.OriginDutyLocation)
- if order.Grade != nil && order.Entitlement != nil {
- order.Entitlement.SetWeightAllotment(string(*order.Grade), order.OrdersType)
- }
var grade string
if order.Grade != nil {
diff --git a/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go b/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go
index 572f4f5dee8..ed333f6fd95 100644
--- a/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go
+++ b/pkg/handlers/primeapiv2/payloads/model_to_payload_test.go
@@ -13,6 +13,7 @@ import (
"github.com/transcom/mymove/pkg/gen/primev2messages"
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/unit"
)
@@ -270,6 +271,7 @@ func (suite *PayloadsSuite) TestSitExtension() {
}
func (suite *PayloadsSuite) TestEntitlement() {
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("Success - Returns the entitlement payload with only required fields", func() {
entitlement := models.Entitlement{
@@ -331,7 +333,9 @@ func (suite *PayloadsSuite) TestEntitlement() {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
@@ -372,7 +376,9 @@ func (suite *PayloadsSuite) TestEntitlement() {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
diff --git a/pkg/handlers/primeapiv3/api.go b/pkg/handlers/primeapiv3/api.go
index bb530557a74..e46f49c8ad1 100644
--- a/pkg/handlers/primeapiv3/api.go
+++ b/pkg/handlers/primeapiv3/api.go
@@ -11,6 +11,7 @@ import (
paymentrequesthelper "github.com/transcom/mymove/pkg/payment_request"
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -31,6 +32,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev3operations.Mymove
fetcher := fetch.NewFetcher(builder)
queryBuilder := query.NewQueryBuilder()
moveRouter := move.NewMoveRouter()
+ waf := entitlements.NewWeightAllotmentFetcher()
primeSpec, err := loads.Analyzed(primev3api.SwaggerJSON, "")
if err != nil {
@@ -45,7 +47,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev3operations.Mymove
primeAPIV3.MoveTaskOrderGetMoveTaskOrderHandler = GetMoveTaskOrderHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
mtoshipment.NewMTOShipmentRateAreaFetcher(),
}
@@ -80,7 +82,7 @@ func NewPrimeAPI(handlerConfig handlers.HandlerConfig) *primev3operations.Mymove
paymentrequest.NewPaymentRequestStatusUpdater(queryBuilder),
)
paymentRequestShipmentRecalculator := paymentrequest.NewPaymentRequestShipmentRecalculator(paymentRequestRecalculator)
- moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := move.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
mtoShipmentUpdater := mtoshipment.NewPrimeMTOShipmentUpdater(
builder,
fetcher,
diff --git a/pkg/handlers/primeapiv3/move_task_order_test.go b/pkg/handlers/primeapiv3/move_task_order_test.go
index b1585307e7b..14b5c5dc9db 100644
--- a/pkg/handlers/primeapiv3/move_task_order_test.go
+++ b/pkg/handlers/primeapiv3/move_task_order_test.go
@@ -17,6 +17,7 @@ import (
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/mocks"
movetaskorder "github.com/transcom/mymove/pkg/services/move_task_order"
mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment"
@@ -26,6 +27,7 @@ import (
func (suite *HandlerSuite) TestGetMoveTaskOrder() {
request := httptest.NewRequest("GET", "/move-task-orders/{moveTaskOrderID}", nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
verifyAddressFields := func(address *models.Address, payload *primev3messages.Address) {
suite.Equal(address.ID.String(), payload.ID.String())
@@ -50,7 +52,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
).Return(nil, nil)
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
mockShipmentRateAreaFinder,
}
return handler
@@ -1367,7 +1369,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
suite.Run("Failure 'Not Found' for non-available move", func() {
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
mtoshipment.NewMTOShipmentRateAreaFetcher(),
}
failureMove := factory.BuildMove(suite.DB(), nil, nil) // default is not available to Prime
@@ -1400,7 +1402,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
// This tests fields that aren't other structs and Addresses
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
mockShipmentRateAreaFinder,
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -1518,7 +1520,7 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
// This tests fields that aren't other structs and Addresses
handler := GetMoveTaskOrderHandler{
suite.HandlerConfig(),
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
mockShipmentRateAreaFinder,
}
successMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
diff --git a/pkg/handlers/primeapiv3/mto_shipment_test.go b/pkg/handlers/primeapiv3/mto_shipment_test.go
index 05db5c0f98d..9a096216deb 100644
--- a/pkg/handlers/primeapiv3/mto_shipment_test.go
+++ b/pkg/handlers/primeapiv3/mto_shipment_test.go
@@ -24,6 +24,7 @@ import (
"github.com/transcom/mymove/pkg/services"
"github.com/transcom/mymove/pkg/services/address"
boatshipment "github.com/transcom/mymove/pkg/services/boat_shipment"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mobilehomeshipment "github.com/transcom/mymove/pkg/services/mobile_home_shipment"
@@ -94,6 +95,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() {
)
shipmentCreator := shipmentorchestrator.NewShipmentCreator(mtoShipmentCreator, ppmShipmentCreator, boatShipmentCreator, mobileHomeShipmentCreator, shipmentRouter, moveTaskOrderUpdater)
mockCreator := mocks.ShipmentCreator{}
+ waf := entitlements.NewWeightAllotmentFetcher()
var pickupAddress primev3messages.Address
var secondaryPickupAddress primev3messages.Address
@@ -106,7 +108,7 @@ func (suite *HandlerSuite) TestCreateMTOShipmentHandler() {
statusUpdater := paymentrequest.NewPaymentRequestStatusUpdater(query.NewQueryBuilder())
recalculator := paymentrequest.NewPaymentRequestRecalculator(creator, statusUpdater)
paymentRequestShipmentRecalculator := paymentrequest.NewPaymentRequestShipmentRecalculator(recalculator)
- moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
ppmShipmentUpdater := ppmshipment.NewPPMShipmentUpdater(&ppmEstimator, addressCreator, addressUpdater)
boatShipmentUpdater := boatshipment.NewBoatShipmentUpdater()
mobileHomeShipmentUpdater := mobilehomeshipment.NewMobileHomeShipmentUpdater()
diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload.go b/pkg/handlers/primeapiv3/payloads/model_to_payload.go
index 3b076b41bf3..22664cc7780 100644
--- a/pkg/handlers/primeapiv3/payloads/model_to_payload.go
+++ b/pkg/handlers/primeapiv3/payloads/model_to_payload.go
@@ -137,9 +137,6 @@ func Order(order *models.Order) *primev3messages.Order {
}
destinationDutyLocation := DutyLocation(&order.NewDutyLocation)
originDutyLocation := DutyLocation(order.OriginDutyLocation)
- if order.Grade != nil && order.Entitlement != nil {
- order.Entitlement.SetWeightAllotment(string(*order.Grade), order.OrdersType)
- }
var grade string
if order.Grade != nil {
diff --git a/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go b/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go
index 666233d4f52..345ee203b0b 100644
--- a/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go
+++ b/pkg/handlers/primeapiv3/payloads/model_to_payload_test.go
@@ -16,6 +16,7 @@ import (
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/unit"
)
@@ -513,7 +514,7 @@ func (suite *PayloadsSuite) TestSitExtension() {
}
func (suite *PayloadsSuite) TestEntitlement() {
-
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("Success - Returns the entitlement payload with only required fields", func() {
entitlement := models.Entitlement{
ID: uuid.Must(uuid.NewV4()),
@@ -574,7 +575,9 @@ func (suite *PayloadsSuite) TestEntitlement() {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
@@ -616,7 +619,9 @@ func (suite *PayloadsSuite) TestEntitlement() {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
diff --git a/pkg/handlers/supportapi/api.go b/pkg/handlers/supportapi/api.go
index 6544b5125f6..e60ec489162 100644
--- a/pkg/handlers/supportapi/api.go
+++ b/pkg/handlers/supportapi/api.go
@@ -12,6 +12,7 @@ import (
"github.com/transcom/mymove/pkg/handlers"
paymentrequesthelper "github.com/transcom/mymove/pkg/payment_request"
"github.com/transcom/mymove/pkg/services/address"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/invoice"
@@ -40,6 +41,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler {
if err != nil {
log.Fatalln(err)
}
+ waf := entitlements.NewWeightAllotmentFetcher()
supportAPI := supportops.NewMymoveAPI(supportSpec)
@@ -47,7 +49,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler {
supportAPI.MoveTaskOrderListMTOsHandler = ListMTOsHandler{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
signedCertificationCreator := signedcertification.NewSignedCertificationCreator()
@@ -69,7 +71,7 @@ func NewSupportAPIHandler(handlerConfig handlers.HandlerConfig) http.Handler {
supportAPI.MoveTaskOrderGetMoveTaskOrderHandler = GetMoveTaskOrderHandlerFunc{
handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher()}
+ movetaskorder.NewMoveTaskOrderFetcher(waf)}
supportAPI.MoveTaskOrderCreateMoveTaskOrderHandler = CreateMoveTaskOrderHandler{
handlerConfig,
diff --git a/pkg/handlers/supportapi/internal/payloads/model_to_payload.go b/pkg/handlers/supportapi/internal/payloads/model_to_payload.go
index 5e43cd2070b..12ebfd4b8a1 100644
--- a/pkg/handlers/supportapi/internal/payloads/model_to_payload.go
+++ b/pkg/handlers/supportapi/internal/payloads/model_to_payload.go
@@ -85,9 +85,6 @@ func Order(order *models.Order) *supportmessages.Order {
destinationDutyLocation := DutyLocation(&order.NewDutyLocation)
originDutyLocation := DutyLocation(order.OriginDutyLocation)
uploadedOrders := Document(&order.UploadedOrders)
- if order.Grade != nil && order.Entitlement != nil {
- order.Entitlement.SetWeightAllotment(string(*order.Grade), order.OrdersType)
- }
reportByDate := strfmt.Date(order.ReportByDate)
issueDate := strfmt.Date(order.IssueDate)
diff --git a/pkg/handlers/supportapi/internal/payloads/model_to_payload_test.go b/pkg/handlers/supportapi/internal/payloads/model_to_payload_test.go
index 05852f8b087..eeb93bc0394 100644
--- a/pkg/handlers/supportapi/internal/payloads/model_to_payload_test.go
+++ b/pkg/handlers/supportapi/internal/payloads/model_to_payload_test.go
@@ -6,22 +6,36 @@ import (
"github.com/go-openapi/strfmt"
"github.com/gofrs/uuid"
- "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/suite"
"github.com/transcom/mymove/pkg/etag"
"github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/handlers"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/notifications"
+ "github.com/transcom/mymove/pkg/services/entitlements"
+ "github.com/transcom/mymove/pkg/testingsuite"
)
-func TestOrder(_ *testing.T) {
- order := &models.Order{}
- Order(order)
+// HandlerSuite is an abstraction of our original suite
+type PayloadsSuite struct {
+ handlers.BaseHandlerTestSuite
}
-func TestEntitlement(t *testing.T) {
+// TestHandlerSuite creates our test suite
+func TestHandlerSuite(t *testing.T) {
+ hs := &PayloadsSuite{
+ BaseHandlerTestSuite: handlers.NewBaseHandlerTestSuite(notifications.NewStubNotificationSender("milmovelocal"), testingsuite.CurrentPackage(),
+ testingsuite.WithPerTestTransaction()),
+ }
- t.Run("Success - Returns the entitlement payload with only required fields", func(t *testing.T) {
+ suite.Run(t, hs)
+ hs.PopTestSuite.TearDown()
+}
+
+func (suite *PayloadsSuite) TestEntitlement() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+ suite.Run("Success - Returns the entitlement payload with only required fields", func() {
entitlement := models.Entitlement{
ID: uuid.Must(uuid.NewV4()),
DependentsAuthorized: nil,
@@ -41,27 +55,27 @@ func TestEntitlement(t *testing.T) {
payload := Entitlement(&entitlement)
- assert.Equal(t, strfmt.UUID(entitlement.ID.String()), payload.ID)
- assert.Equal(t, int64(0), payload.RequiredMedicalEquipmentWeight)
- assert.Equal(t, false, payload.OrganizationalClothingAndIndividualEquipment)
- assert.Equal(t, int64(0), payload.ProGearWeight)
- assert.Equal(t, int64(0), payload.ProGearWeightSpouse)
- assert.NotEmpty(t, payload.ETag)
- assert.Equal(t, etag.GenerateEtag(entitlement.UpdatedAt), payload.ETag)
+ suite.Equal(strfmt.UUID(entitlement.ID.String()), payload.ID)
+ suite.Equal(int64(0), payload.RequiredMedicalEquipmentWeight)
+ suite.Equal(false, payload.OrganizationalClothingAndIndividualEquipment)
+ suite.Equal(int64(0), payload.ProGearWeight)
+ suite.Equal(int64(0), payload.ProGearWeightSpouse)
+ suite.NotEmpty(payload.ETag)
+ suite.Equal(etag.GenerateEtag(entitlement.UpdatedAt), payload.ETag)
- assert.Nil(t, payload.AuthorizedWeight)
- assert.Nil(t, payload.DependentsAuthorized)
- assert.Nil(t, payload.NonTemporaryStorage)
- assert.Nil(t, payload.PrivatelyOwnedVehicle)
+ suite.Nil(payload.AuthorizedWeight)
+ suite.Nil(payload.DependentsAuthorized)
+ suite.Nil(payload.NonTemporaryStorage)
+ suite.Nil(payload.PrivatelyOwnedVehicle)
/* These fields are defaulting to zero if they are nil in the model */
- assert.Equal(t, int64(0), payload.StorageInTransit)
- assert.Equal(t, int64(0), payload.TotalDependents)
- assert.Equal(t, int64(0), payload.TotalWeight)
- assert.Equal(t, int64(0), *payload.UnaccompaniedBaggageAllowance)
+ suite.Equal(int64(0), payload.StorageInTransit)
+ suite.Equal(int64(0), payload.TotalDependents)
+ suite.Equal(int64(0), payload.TotalWeight)
+ suite.Equal(int64(0), *payload.UnaccompaniedBaggageAllowance)
})
- t.Run("Success - Returns the entitlement payload with all optional fields populated", func(t *testing.T) {
+ suite.Run("Success - Returns the entitlement payload with all optional fields populated", func() {
entitlement := models.Entitlement{
ID: uuid.Must(uuid.NewV4()),
DependentsAuthorized: handlers.FmtBool(true),
@@ -81,28 +95,30 @@ func TestEntitlement(t *testing.T) {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
- assert.Equal(t, strfmt.UUID(entitlement.ID.String()), payload.ID)
- assert.True(t, *payload.DependentsAuthorized)
- assert.Equal(t, int64(2), payload.TotalDependents)
- assert.True(t, *payload.NonTemporaryStorage)
- assert.True(t, *payload.PrivatelyOwnedVehicle)
- assert.Equal(t, int64(10000), *payload.AuthorizedWeight)
- assert.Equal(t, int64(400), *payload.UnaccompaniedBaggageAllowance)
- assert.Equal(t, int64(9000), payload.TotalWeight)
- assert.Equal(t, int64(45), payload.StorageInTransit)
- assert.Equal(t, int64(500), payload.RequiredMedicalEquipmentWeight)
- assert.Equal(t, true, payload.OrganizationalClothingAndIndividualEquipment)
- assert.Equal(t, int64(1000), payload.ProGearWeight)
- assert.Equal(t, int64(750), payload.ProGearWeightSpouse)
- assert.NotEmpty(t, payload.ETag)
- assert.Equal(t, etag.GenerateEtag(entitlement.UpdatedAt), payload.ETag)
+ suite.Equal(strfmt.UUID(entitlement.ID.String()), payload.ID)
+ suite.True(*payload.DependentsAuthorized)
+ suite.Equal(int64(2), payload.TotalDependents)
+ suite.True(*payload.NonTemporaryStorage)
+ suite.True(*payload.PrivatelyOwnedVehicle)
+ suite.Equal(int64(10000), *payload.AuthorizedWeight)
+ suite.Equal(int64(400), *payload.UnaccompaniedBaggageAllowance)
+ suite.Equal(int64(9000), payload.TotalWeight)
+ suite.Equal(int64(45), payload.StorageInTransit)
+ suite.Equal(int64(500), payload.RequiredMedicalEquipmentWeight)
+ suite.Equal(true, payload.OrganizationalClothingAndIndividualEquipment)
+ suite.Equal(int64(1000), payload.ProGearWeight)
+ suite.Equal(int64(750), payload.ProGearWeightSpouse)
+ suite.NotEmpty(payload.ETag)
+ suite.Equal(etag.GenerateEtag(entitlement.UpdatedAt), payload.ETag)
})
- t.Run("Success - Returns the entitlement payload with total weight self when dependents are not authorized", func(t *testing.T) {
+ suite.Run("Success - Returns the entitlement payload with total weight self when dependents are not authorized", func() {
entitlement := models.Entitlement{
ID: uuid.Must(uuid.NewV4()),
DependentsAuthorized: handlers.FmtBool(false),
@@ -122,24 +138,26 @@ func TestEntitlement(t *testing.T) {
// TotalWeight needs to read from the internal weightAllotment, in this case 7000 lbs w/o dependents and
// 9000 lbs with dependents
- entitlement.SetWeightAllotment(string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE5), internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.NoError(err)
+ entitlement.WeightAllotted = &allotment
payload := Entitlement(&entitlement)
- assert.Equal(t, strfmt.UUID(entitlement.ID.String()), payload.ID)
- assert.False(t, *payload.DependentsAuthorized)
- assert.Equal(t, int64(2), payload.TotalDependents)
- assert.True(t, *payload.NonTemporaryStorage)
- assert.True(t, *payload.PrivatelyOwnedVehicle)
- assert.Equal(t, int64(10000), *payload.AuthorizedWeight)
- assert.Equal(t, int64(400), *payload.UnaccompaniedBaggageAllowance)
- assert.Equal(t, int64(7000), payload.TotalWeight)
- assert.Equal(t, int64(45), payload.StorageInTransit)
- assert.Equal(t, int64(500), payload.RequiredMedicalEquipmentWeight)
- assert.Equal(t, true, payload.OrganizationalClothingAndIndividualEquipment)
- assert.Equal(t, int64(1000), payload.ProGearWeight)
- assert.Equal(t, int64(750), payload.ProGearWeightSpouse)
- assert.NotEmpty(t, payload.ETag)
- assert.Equal(t, etag.GenerateEtag(entitlement.UpdatedAt), payload.ETag)
+ suite.Equal(strfmt.UUID(entitlement.ID.String()), payload.ID)
+ suite.False(*payload.DependentsAuthorized)
+ suite.Equal(int64(2), payload.TotalDependents)
+ suite.True(*payload.NonTemporaryStorage)
+ suite.True(*payload.PrivatelyOwnedVehicle)
+ suite.Equal(int64(10000), *payload.AuthorizedWeight)
+ suite.Equal(int64(400), *payload.UnaccompaniedBaggageAllowance)
+ suite.Equal(int64(7000), payload.TotalWeight)
+ suite.Equal(int64(45), payload.StorageInTransit)
+ suite.Equal(int64(500), payload.RequiredMedicalEquipmentWeight)
+ suite.Equal(true, payload.OrganizationalClothingAndIndividualEquipment)
+ suite.Equal(int64(1000), payload.ProGearWeight)
+ suite.Equal(int64(750), payload.ProGearWeightSpouse)
+ suite.NotEmpty(payload.ETag)
+ suite.Equal(etag.GenerateEtag(entitlement.UpdatedAt), payload.ETag)
})
}
diff --git a/pkg/handlers/supportapi/move_task_order_test.go b/pkg/handlers/supportapi/move_task_order_test.go
index b1241de3f32..f5663ae8794 100644
--- a/pkg/handlers/supportapi/move_task_order_test.go
+++ b/pkg/handlers/supportapi/move_task_order_test.go
@@ -18,6 +18,7 @@ import (
"github.com/transcom/mymove/pkg/models"
routemocks "github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
"github.com/transcom/mymove/pkg/services/mocks"
moverouter "github.com/transcom/mymove/pkg/services/move"
@@ -31,6 +32,7 @@ import (
func (suite *HandlerSuite) TestListMTOsHandler() {
// unavailable MTO
factory.BuildMove(suite.DB(), nil, nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
moveTaskOrder := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -55,7 +57,7 @@ func (suite *HandlerSuite) TestListMTOsHandler() {
handler := ListMTOsHandler{
HandlerConfig: handlerConfig,
- MoveTaskOrderFetcher: movetaskorder.NewMoveTaskOrderFetcher(),
+ MoveTaskOrderFetcher: movetaskorder.NewMoveTaskOrderFetcher(waf),
}
response := handler.Handle(params)
@@ -227,10 +229,11 @@ func (suite *HandlerSuite) TestGetMoveTaskOrder() {
HTTPRequest: request,
MoveTaskOrderID: move.ID.String(),
}
+ waf := entitlements.NewWeightAllotmentFetcher()
handlerConfig := suite.HandlerConfig()
handler := GetMoveTaskOrderHandlerFunc{handlerConfig,
- movetaskorder.NewMoveTaskOrderFetcher(),
+ movetaskorder.NewMoveTaskOrderFetcher(waf),
}
response := handler.Handle(params)
suite.IsNotErrResponse(response)
diff --git a/pkg/models/application_parameters.go b/pkg/models/application_parameters.go
index dccf21fd10f..083605c9383 100644
--- a/pkg/models/application_parameters.go
+++ b/pkg/models/application_parameters.go
@@ -1,6 +1,7 @@
package models
import (
+ "encoding/json"
"time"
"github.com/gobuffalo/pop/v6"
@@ -10,12 +11,13 @@ import (
// ApplicationParameters is a model representing application parameters and holds parameter values and parameter names stored in the database
type ApplicationParameters struct {
- ID uuid.UUID `json:"id" db:"id"`
- ValidationCode *string `json:"validation_code" db:"validation_code"`
- ParameterName *string `json:"parameter_name" db:"parameter_name"`
- ParameterValue *string `json:"parameter_value" db:"parameter_value"`
- CreatedAt time.Time `json:"created_at" db:"created_at"`
- UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
+ ID uuid.UUID `json:"id" db:"id"`
+ ValidationCode *string `json:"validation_code" db:"validation_code"`
+ ParameterName *string `json:"parameter_name" db:"parameter_name"`
+ ParameterValue *string `json:"parameter_value" db:"parameter_value"`
+ ParameterJson *json.RawMessage `json:"parameter_json" db:"parameter_json"`
+ CreatedAt time.Time `json:"created_at" db:"created_at"`
+ UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
func (a ApplicationParameters) TableName() string {
diff --git a/pkg/models/entitlements.go b/pkg/models/entitlements.go
deleted file mode 100644
index 94fa25f6ef2..00000000000
--- a/pkg/models/entitlements.go
+++ /dev/null
@@ -1,365 +0,0 @@
-package models
-
-import (
- "fmt"
-
- "github.com/pkg/errors"
-
- "github.com/transcom/mymove/pkg/appcontext"
- "github.com/transcom/mymove/pkg/gen/internalmessages"
-)
-
-// WeightAllotment represents the weights allotted for a rank
-type WeightAllotment struct {
- TotalWeightSelf int
- TotalWeightSelfPlusDependents int
- ProGearWeight int
- ProGearWeightSpouse int
- UnaccompaniedBaggageAllowance int
-}
-
-// the midshipman entitlement is shared with service academy cadet
-var midshipman = WeightAllotment{
- TotalWeightSelf: 350,
- TotalWeightSelfPlusDependents: 350,
- ProGearWeight: 0,
- ProGearWeightSpouse: 0,
-}
-
-var aviationCadet = WeightAllotment{
- TotalWeightSelf: 7000,
- TotalWeightSelfPlusDependents: 8000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e1 = WeightAllotment{
- TotalWeightSelf: 5000,
- TotalWeightSelfPlusDependents: 8000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e2 = WeightAllotment{
- TotalWeightSelf: 5000,
- TotalWeightSelfPlusDependents: 8000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e3 = WeightAllotment{
- TotalWeightSelf: 5000,
- TotalWeightSelfPlusDependents: 8000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e4 = WeightAllotment{
- TotalWeightSelf: 7000,
- TotalWeightSelfPlusDependents: 8000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e5 = WeightAllotment{
- TotalWeightSelf: 7000,
- TotalWeightSelfPlusDependents: 9000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e6 = WeightAllotment{
- TotalWeightSelf: 8000,
- TotalWeightSelfPlusDependents: 11000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e7 = WeightAllotment{
- TotalWeightSelf: 11000,
- TotalWeightSelfPlusDependents: 13000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e8 = WeightAllotment{
- TotalWeightSelf: 12000,
- TotalWeightSelfPlusDependents: 14000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e9 = WeightAllotment{
- TotalWeightSelf: 13000,
- TotalWeightSelfPlusDependents: 15000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var e9SpecialSeniorEnlisted = WeightAllotment{
- TotalWeightSelf: 14000,
- TotalWeightSelfPlusDependents: 17000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-// O-1 through O-5 share their entitlements with W-1 through W-5
-var o1W1AcademyGraduate = WeightAllotment{
- TotalWeightSelf: 10000,
- TotalWeightSelfPlusDependents: 12000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o2W2 = WeightAllotment{
- TotalWeightSelf: 12500,
- TotalWeightSelfPlusDependents: 13500,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o3W3 = WeightAllotment{
- TotalWeightSelf: 13000,
- TotalWeightSelfPlusDependents: 14500,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o4W4 = WeightAllotment{
- TotalWeightSelf: 14000,
- TotalWeightSelfPlusDependents: 17000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o5W5 = WeightAllotment{
- TotalWeightSelf: 16000,
- TotalWeightSelfPlusDependents: 17500,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o6 = WeightAllotment{
- TotalWeightSelf: 18000,
- TotalWeightSelfPlusDependents: 18000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o7 = WeightAllotment{
- TotalWeightSelf: 18000,
- TotalWeightSelfPlusDependents: 18000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o8 = WeightAllotment{
- TotalWeightSelf: 18000,
- TotalWeightSelfPlusDependents: 18000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o9 = WeightAllotment{
- TotalWeightSelf: 18000,
- TotalWeightSelfPlusDependents: 18000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var o10 = WeightAllotment{
- TotalWeightSelf: 18000,
- TotalWeightSelfPlusDependents: 18000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-var civilianEmployee = WeightAllotment{
- TotalWeightSelf: 18000,
- TotalWeightSelfPlusDependents: 18000,
- ProGearWeight: 2000,
- ProGearWeightSpouse: 500,
-}
-
-// allotment by orders type
-var studentTravel = WeightAllotment{
- TotalWeightSelf: 350,
- TotalWeightSelfPlusDependents: 350,
- ProGearWeight: 0,
- ProGearWeightSpouse: 0,
-}
-
-var entitlements = map[internalmessages.OrderPayGrade]WeightAllotment{
- ServiceMemberGradeACADEMYCADET: midshipman,
- ServiceMemberGradeAVIATIONCADET: aviationCadet,
- ServiceMemberGradeE1: e1,
- ServiceMemberGradeE2: e2,
- ServiceMemberGradeE3: e3,
- ServiceMemberGradeE4: e4,
- ServiceMemberGradeE5: e5,
- ServiceMemberGradeE6: e6,
- ServiceMemberGradeE7: e7,
- ServiceMemberGradeE8: e8,
- ServiceMemberGradeE9: e9,
- ServiceMemberGradeE9SPECIALSENIORENLISTED: e9SpecialSeniorEnlisted,
- ServiceMemberGradeMIDSHIPMAN: midshipman,
- ServiceMemberGradeO1ACADEMYGRADUATE: o1W1AcademyGraduate,
- ServiceMemberGradeO2: o2W2,
- ServiceMemberGradeO3: o3W3,
- ServiceMemberGradeO4: o4W4,
- ServiceMemberGradeO5: o5W5,
- ServiceMemberGradeO6: o6,
- ServiceMemberGradeO7: o7,
- ServiceMemberGradeO8: o8,
- ServiceMemberGradeO9: o9,
- ServiceMemberGradeO10: o10,
- ServiceMemberGradeW1: o1W1AcademyGraduate,
- ServiceMemberGradeW2: o2W2,
- ServiceMemberGradeW3: o3W3,
- ServiceMemberGradeW4: o4W4,
- ServiceMemberGradeW5: o5W5,
- ServiceMemberGradeCIVILIANEMPLOYEE: civilianEmployee,
-}
-
-var entitlementsByOrdersType = map[internalmessages.OrdersType]WeightAllotment{
- internalmessages.OrdersTypeSTUDENTTRAVEL: studentTravel,
-}
-
-func getEntitlement(grade internalmessages.OrderPayGrade) (WeightAllotment, error) {
- if entitlement, ok := entitlements[grade]; ok {
- return entitlement, nil
- }
- return WeightAllotment{}, fmt.Errorf("no entitlement found for pay grade %s", grade)
-}
-
-func getEntitlementByOrdersType(ordersType internalmessages.OrdersType) (WeightAllotment, error) {
- if entitlement, ok := entitlementsByOrdersType[ordersType]; ok {
- return entitlement, nil
- }
- return WeightAllotment{}, fmt.Errorf("no entitlement found for orders type %s", ordersType)
-}
-
-// AllWeightAllotments returns all the weight allotments for each rank.
-func AllWeightAllotments() map[internalmessages.OrderPayGrade]WeightAllotment {
- return entitlements
-}
-
-// GetWeightAllotment returns the weight allotments for a given pay grade or an orders type.
-func GetWeightAllotment(grade internalmessages.OrderPayGrade, ordersType internalmessages.OrdersType) WeightAllotment {
- var entitlement WeightAllotment
- var err error
-
- if ordersType == internalmessages.OrdersTypeSTUDENTTRAVEL { // currently only applies to student travel order that limits overall authorized weight
- entitlement, err = getEntitlementByOrdersType(ordersType)
- } else {
- entitlement, err = getEntitlement(grade)
- }
- if err != nil {
- return WeightAllotment{}
- }
- return entitlement
-}
-
-// GetUBWeightAllowance returns the UB weight allowance for a UB shipment, part of the overall entitlements for an order
-func GetUBWeightAllowance(appCtx appcontext.AppContext, originDutyLocationIsOconus *bool, newDutyLocationIsOconus *bool, branch *ServiceMemberAffiliation, grade *internalmessages.OrderPayGrade, orderType *internalmessages.OrdersType, dependentsAuthorized *bool, isAccompaniedTour *bool, dependentsUnderTwelve *int, dependentsTwelveAndOver *int) (int, error) {
- originDutyLocationIsOconusValue := false
- if originDutyLocationIsOconus != nil {
- originDutyLocationIsOconusValue = *originDutyLocationIsOconus
- }
- newDutyLocationIsOconusValue := false
- if newDutyLocationIsOconus != nil {
- newDutyLocationIsOconusValue = *newDutyLocationIsOconus
- }
- branchOfService := ""
- if branch != nil {
- branchOfService = string(*branch)
- }
- orderPayGrade := ""
- if grade != nil {
- orderPayGrade = string(*grade)
- }
- typeOfOrder := ""
- if orderType != nil {
- typeOfOrder = string(*orderType)
- }
- dependentsAreAuthorized := false
- if dependentsAuthorized != nil {
- dependentsAreAuthorized = *dependentsAuthorized
- }
- isAnAccompaniedTour := false
- if isAccompaniedTour != nil {
- isAnAccompaniedTour = *isAccompaniedTour
- }
- underTwelveDependents := 0
- if dependentsUnderTwelve != nil {
- underTwelveDependents = *dependentsUnderTwelve
- }
- twelveAndOverDependents := 0
- if dependentsTwelveAndOver != nil {
- twelveAndOverDependents = *dependentsTwelveAndOver
- }
-
- // only calculate UB allowance if either origin or new duty locations are OCONUS
- if originDutyLocationIsOconusValue || newDutyLocationIsOconusValue {
-
- const civilianBaseUBAllowance = 350
- const dependents12AndOverUBAllowance = 350
- const depedentsUnder12UBAllowance = 175
- const maxWholeFamilyCivilianUBAllowance = 2000
- const studentTravelMaxAllowance = 350
- ubAllowance := 0
-
- if typeOfOrder == string(internalmessages.OrdersTypeSTUDENTTRAVEL) {
- ubAllowance = studentTravelMaxAllowance
- } else if orderPayGrade == string(internalmessages.OrderPayGradeCIVILIANEMPLOYEE) && dependentsAreAuthorized && underTwelveDependents == 0 && twelveAndOverDependents == 0 {
- ubAllowance = civilianBaseUBAllowance
- } else if orderPayGrade == string(internalmessages.OrderPayGradeCIVILIANEMPLOYEE) && dependentsAreAuthorized && (underTwelveDependents > 0 || twelveAndOverDependents > 0) {
- ubAllowance = civilianBaseUBAllowance
- // for each dependent 12 and older, add an additional 350 lbs to the civilian's baggage allowance
- ubAllowance += twelveAndOverDependents * dependents12AndOverUBAllowance
- // for each dependent under 12, add an additional 175 lbs to the civilian's baggage allowance
- ubAllowance += underTwelveDependents * depedentsUnder12UBAllowance
- // max allowance of 2,000 lbs for entire family
- if ubAllowance > maxWholeFamilyCivilianUBAllowance {
- ubAllowance = maxWholeFamilyCivilianUBAllowance
- }
- } else {
- if typeOfOrder == string(internalmessages.OrdersTypeLOCALMOVE) {
- // no UB allowance for local moves
- return 0, nil
- } else if typeOfOrder != string(internalmessages.OrdersTypeTEMPORARYDUTY) {
- // all order types other than temporary duty are treated as permanent change of station types for the lookup
- typeOfOrder = string(internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
- }
- // space force members entitled to the same allowance as air force members
- if branchOfService == AffiliationSPACEFORCE.String() {
- branchOfService = AffiliationAIRFORCE.String()
- }
- // e9 special senior enlisted members entitled to the same allowance as e9 members
- if orderPayGrade == string(ServiceMemberGradeE9SPECIALSENIORENLISTED) {
- orderPayGrade = string(ServiceMemberGradeE9)
- }
-
- var baseUBAllowance UBAllowances
- err := appCtx.DB().Where("branch = ? AND grade = ? AND orders_type = ? AND dependents_authorized = ? AND accompanied_tour = ?", branchOfService, orderPayGrade, typeOfOrder, dependentsAreAuthorized, isAnAccompaniedTour).First(&baseUBAllowance)
- if err != nil {
- if errors.Cause(err).Error() == RecordNotFoundErrorString {
- message := fmt.Sprintf("No UB allowance entry found in ub_allowances table for branch: %s, grade: %s, orders_type: %s, dependents_authorized: %t, accompanied_tour: %t.", branchOfService, orderPayGrade, typeOfOrder, dependentsAreAuthorized, isAnAccompaniedTour)
- appCtx.Logger().Info(message)
- return 0, nil
- }
- return 0, err
- }
- if baseUBAllowance.UBAllowance != nil {
- ubAllowance = *baseUBAllowance.UBAllowance
- return ubAllowance, nil
- } else {
- return 0, nil
- }
- }
- return ubAllowance, nil
- } else {
- appCtx.Logger().Info("No OCONUS duty location found for orders, no UB allowance calculated as part of order entitlement.")
- return 0, nil
- }
-}
diff --git a/pkg/models/entitlements_test.go b/pkg/models/entitlements_test.go
deleted file mode 100644
index 6ab3e576bd8..00000000000
--- a/pkg/models/entitlements_test.go
+++ /dev/null
@@ -1,278 +0,0 @@
-package models_test
-
-import (
- "github.com/transcom/mymove/pkg/gen/internalmessages"
- "github.com/transcom/mymove/pkg/models"
-)
-
-const civilianBaseUBAllowanceTestConstant = 350
-const dependents12AndOverUBAllowanceTestConstant = 350
-const depedentsUnder12UBAllowanceTestConstant = 175
-const maxWholeFamilyCivilianUBAllowanceTestConstant = 2000
-
-func (suite *ModelSuite) TestGetEntitlementWithValidValues() {
- E1 := models.ServiceMemberGradeE1
- ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
-
- suite.Run("E1 with dependents", func() {
- E1FullLoad := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(8000, E1FullLoad.TotalWeightSelfPlusDependents)
- })
-
- suite.Run("E1 without dependents", func() {
- E1Solo := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(5000, E1Solo.TotalWeightSelf)
- })
-
- suite.Run("E1 Pro Gear", func() {
- E1ProGear := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(2000, E1ProGear.ProGearWeight)
- })
-
- suite.Run("E1 Pro Gear Spouse", func() {
- E1ProGearSpouse := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(500, E1ProGearSpouse.ProGearWeightSpouse)
- })
-}
-
-func (suite *ModelSuite) TestGetUBWeightAllowanceIsZero() {
- appCtx := suite.AppContextForTest()
- branch := models.AffiliationMARINES
- originDutyLocationIsOconus := false
- newDutyLocationIsOconus := false
- grade := models.ServiceMemberGradeE1
- orderType := internalmessages.OrdersTypeLOCALMOVE
- dependentsAuthorized := true
- isAccompaniedTour := true
- dependentsUnderTwelve := 2
- dependentsTwelveAndOver := 1
-
- suite.Run("UB allowance is zero when origin and new duty location are both CONUS", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(0, ubAllowance)
- })
-
- suite.Run("UB allowance is zero for orders type OrdersTypeLOCALMOVE", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(0, ubAllowance)
- })
-
- originDutyLocationIsOconus = true
- orderType = internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- dependentsAuthorized = false
- suite.Run("UB allowance is zero for nonexistent combination of branch, grade, orders_type, dependents_authorized, and accompanied_tour", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(0, ubAllowance)
- })
-}
-
-func (suite *ModelSuite) TestGetUBWeightAllowanceCivilians() {
- appCtx := suite.AppContextForTest()
- branch := models.AffiliationCOASTGUARD
- originDutyLocationIsOconus := true
- newDutyLocationIsOconus := false
- grade := models.ServiceMemberGradeCIVILIANEMPLOYEE
- orderType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- dependentsAuthorized := true
- isAccompaniedTour := true
-
- dependentsUnderTwelve := 0
- dependentsTwelveAndOver := 0
- suite.Run("UB allowance is calculated for Civilian Employee pay grade with no dependents", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(civilianBaseUBAllowanceTestConstant, ubAllowance)
- })
-
- dependentsUnderTwelve = 0
- dependentsTwelveAndOver = 2
- suite.Run("UB allowance is calculated for Civilian Employee pay grade when dependentsUnderTwelve is 0 and dependentsTwelveAndOver is > 0", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- civilianPlusDependentsTotalBaggageAllowance := civilianBaseUBAllowanceTestConstant + (dependentsUnderTwelve * depedentsUnder12UBAllowanceTestConstant) + (dependentsTwelveAndOver * dependents12AndOverUBAllowanceTestConstant)
- suite.Assertions.Equal(1050, civilianPlusDependentsTotalBaggageAllowance)
- suite.Assertions.Equal(civilianPlusDependentsTotalBaggageAllowance, ubAllowance)
- })
-
- dependentsUnderTwelve = 3
- dependentsTwelveAndOver = 0
- suite.Run("UB allowance is calculated for Civilian Employee pay grade when dependentsUnderTwelve is > 0 and dependentsTwelveAndOver is 0", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- civilianPlusDependentsTotalBaggageAllowance := civilianBaseUBAllowanceTestConstant + (dependentsUnderTwelve * depedentsUnder12UBAllowanceTestConstant) + (dependentsTwelveAndOver * dependents12AndOverUBAllowanceTestConstant)
- suite.Assertions.Equal(875, civilianPlusDependentsTotalBaggageAllowance)
- suite.Assertions.Equal(civilianPlusDependentsTotalBaggageAllowance, ubAllowance)
- })
-
- dependentsUnderTwelve = 2
- dependentsTwelveAndOver = 1
- suite.Run("UB allowance is calculated for Civilian Employee pay grade", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- civilianPlusDependentsTotalBaggageAllowance := civilianBaseUBAllowanceTestConstant + (dependentsUnderTwelve * depedentsUnder12UBAllowanceTestConstant) + (dependentsTwelveAndOver * dependents12AndOverUBAllowanceTestConstant)
- suite.Assertions.Equal(1050, civilianPlusDependentsTotalBaggageAllowance)
- suite.Assertions.Equal(civilianPlusDependentsTotalBaggageAllowance, ubAllowance)
- })
-
- dependentsUnderTwelve = 3
- dependentsTwelveAndOver = 4
- // this combination of depdendents would tally up to 2275 pounds normally
- // however, we limit the max ub allowance for a family to 2000
- suite.Run("UB allowance is set to 2000 for the max weight for a family", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- civilianPlusDependentsTotalBaggageAllowance := civilianBaseUBAllowanceTestConstant + (dependentsUnderTwelve * depedentsUnder12UBAllowanceTestConstant) + (dependentsTwelveAndOver * dependents12AndOverUBAllowanceTestConstant)
- suite.Assertions.Equal(2275, civilianPlusDependentsTotalBaggageAllowance)
- suite.Assertions.NotEqual(civilianPlusDependentsTotalBaggageAllowance, ubAllowance)
- suite.Assertions.Equal(maxWholeFamilyCivilianUBAllowanceTestConstant, ubAllowance)
- })
-
- orderType = internalmessages.OrdersTypeSTUDENTTRAVEL
- // This should limit the ub allowance to 350 lbs because it is a Student Travel order type
- suite.Run("UB allowance is set to 350 for Student Travel orders", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(350, ubAllowance)
- })
-}
-
-func (suite *ModelSuite) TestGetUBWeightAllowanceEdgeCases() {
-
- appCtx := suite.AppContextForTest()
- branch := models.AffiliationAIRFORCE
- originDutyLocationIsOconus := true
- newDutyLocationIsOconus := false
- grade := models.ServiceMemberGradeE1
- orderType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- dependentsAuthorized := true
- isAccompaniedTour := true
- dependentsUnderTwelve := 0
- dependentsTwelveAndOver := 0
-
- suite.Run("Air Force gets a UB allowance", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- branch = models.AffiliationSPACEFORCE
- suite.Run("Space Force gets the same UB allowance as Air Force", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- branch = models.AffiliationNAVY
- grade = models.ServiceMemberGradeE9
- suite.Run("Pay grade E9 gets a UB allowance", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- grade = models.ServiceMemberGradeE9SPECIALSENIORENLISTED
- suite.Run("Pay grade E9 Special Senior Enlisted and pay grade E9 get the same UB allowance", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-}
-
-func (suite *ModelSuite) TestGetUBWeightAllowanceWithValidValues() {
- appCtx := suite.AppContextForTest()
- branch := models.AffiliationMARINES
- originDutyLocationIsOconus := true
- newDutyLocationIsOconus := false
- grade := models.ServiceMemberGradeE1
- orderType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- dependentsAuthorized := true
- isAccompaniedTour := true
- dependentsUnderTwelve := 2
- dependentsTwelveAndOver := 4
-
- suite.Run("UB allowance is calculated when origin duty location is OCONUS", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- originDutyLocationIsOconus = false
- newDutyLocationIsOconus = true
- suite.Run("UB allowance is calculated when new duty location is OCONUS", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- suite.Run("OCONUS, Marines, E1, PCS, dependents are authorized, is accompanied = 2000 lbs", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- suite.Run("OCONUS, Marines, E1, PCS, dependents are authorized, is accompanied = 2000 lbs", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- branch = models.AffiliationAIRFORCE
- suite.Run("OCONUS, Air Force, E1, PCS, dependents are authorized, is accompanied = 2000 lbs", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(2000, ubAllowance)
- })
-
- orderType = internalmessages.OrdersTypeTEMPORARYDUTY
- dependentsAuthorized = false
- isAccompaniedTour = false
- suite.Run("OCONUS, Air Force, E1, Temporary Duty, dependents are NOT authorized, is NOT accompanied = 400 lbs", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(400, ubAllowance)
- })
-
- grade = models.ServiceMemberGradeW2
- retirementOrderType := internalmessages.OrdersTypeRETIREMENT
- orderType = internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- suite.Run("Orders type of Retirement returns same entitlement value as the PCS orders type in the database", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &retirementOrderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(600, ubAllowance)
- })
-
- orderType = internalmessages.OrdersTypeTEMPORARYDUTY
- suite.Run("OCONUS, Air Force, W1, Temporary Duty, dependents are NOT authorized, is NOT accompanied = 600", func() {
- ubAllowance, err := models.GetUBWeightAllowance(appCtx, &originDutyLocationIsOconus, &newDutyLocationIsOconus, &branch, &grade, &orderType, &dependentsAuthorized, &isAccompaniedTour, &dependentsUnderTwelve, &dependentsTwelveAndOver)
- suite.NoError(err)
- suite.Assertions.Equal(600, ubAllowance)
- })
-}
-
-func (suite *ModelSuite) TestGetEntitlementByOrdersTypeWithValidValues() {
- E1 := models.ServiceMemberGradeE1
- ordersType := internalmessages.OrdersTypeSTUDENTTRAVEL
-
- suite.Run("Student Travel with dependents", func() {
- STFullLoad := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(350, STFullLoad.TotalWeightSelfPlusDependents)
- })
-
- suite.Run("Student Travel without dependents", func() {
- STSolo := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(350, STSolo.TotalWeightSelf)
- })
-
- suite.Run("Student Travel Pro Gear", func() {
- STProGear := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(0, STProGear.ProGearWeight)
- })
-
- suite.Run("Student Travel Pro Gear Spouse", func() {
- STProGearSpouse := models.GetWeightAllotment(E1, ordersType)
- suite.Assertions.Equal(0, STProGearSpouse.ProGearWeightSpouse)
- })
-}
diff --git a/pkg/models/ghc_entitlements.go b/pkg/models/ghc_entitlements.go
index 383caada3a7..f56c915ad19 100644
--- a/pkg/models/ghc_entitlements.go
+++ b/pkg/models/ghc_entitlements.go
@@ -1,13 +1,16 @@
package models
import (
+ "fmt"
"time"
"github.com/gobuffalo/pop/v6"
"github.com/gobuffalo/validate/v3"
"github.com/gobuffalo/validate/v3/validators"
"github.com/gofrs/uuid"
+ "github.com/pkg/errors"
+ "github.com/transcom/mymove/pkg/appcontext"
"github.com/transcom/mymove/pkg/gen/internalmessages"
)
@@ -31,6 +34,7 @@ type Entitlement struct {
OrganizationalClothingAndIndividualEquipment bool `db:"organizational_clothing_and_individual_equipment"`
ProGearWeight int `db:"pro_gear_weight"`
ProGearWeightSpouse int `db:"pro_gear_weight_spouse"`
+ WeightRestriction *int `db:"weight_restriction"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
@@ -66,15 +70,6 @@ func (e *Entitlement) Validate(*pop.Connection) (*validate.Errors, error) {
return validate.Validate(vs...), nil
}
-// SetWeightAllotment sets the weight allotment
-// TODO probably want to reconsider keeping grade a string rather than enum
-// TODO and possibly consider creating ghc specific GetWeightAllotment should the two
-// TODO diverge in the future
-func (e *Entitlement) SetWeightAllotment(grade string, ordersType internalmessages.OrdersType) {
- wa := GetWeightAllotment(internalmessages.OrderPayGrade(grade), ordersType)
- e.WeightAllotted = &wa
-}
-
// WeightAllotment returns the weight allotment
func (e *Entitlement) WeightAllotment() *WeightAllotment {
return e.WeightAllotted
@@ -129,3 +124,116 @@ func (e *Entitlement) UBWeightAllowance() *int {
return nil
}
}
+
+// GetUBWeightAllowance returns the UB weight allowance for a UB shipment, part of the overall entitlements for an order
+func GetUBWeightAllowance(appCtx appcontext.AppContext, originDutyLocationIsOconus *bool, newDutyLocationIsOconus *bool, branch *ServiceMemberAffiliation, grade *internalmessages.OrderPayGrade, orderType *internalmessages.OrdersType, dependentsAuthorized *bool, isAccompaniedTour *bool, dependentsUnderTwelve *int, dependentsTwelveAndOver *int) (int, error) {
+ originDutyLocationIsOconusValue := false
+ if originDutyLocationIsOconus != nil {
+ originDutyLocationIsOconusValue = *originDutyLocationIsOconus
+ }
+ newDutyLocationIsOconusValue := false
+ if newDutyLocationIsOconus != nil {
+ newDutyLocationIsOconusValue = *newDutyLocationIsOconus
+ }
+ branchOfService := ""
+ if branch != nil {
+ branchOfService = string(*branch)
+ }
+ orderPayGrade := ""
+ if grade != nil {
+ orderPayGrade = string(*grade)
+ }
+ typeOfOrder := ""
+ if orderType != nil {
+ typeOfOrder = string(*orderType)
+ }
+ dependentsAreAuthorized := false
+ if dependentsAuthorized != nil {
+ dependentsAreAuthorized = *dependentsAuthorized
+ }
+ isAnAccompaniedTour := false
+ if isAccompaniedTour != nil {
+ isAnAccompaniedTour = *isAccompaniedTour
+ }
+ underTwelveDependents := 0
+ if dependentsUnderTwelve != nil {
+ underTwelveDependents = *dependentsUnderTwelve
+ }
+ twelveAndOverDependents := 0
+ if dependentsTwelveAndOver != nil {
+ twelveAndOverDependents = *dependentsTwelveAndOver
+ }
+
+ // only calculate UB allowance if either origin or new duty locations are OCONUS
+ if originDutyLocationIsOconusValue || newDutyLocationIsOconusValue {
+
+ const civilianBaseUBAllowance = 350
+ const dependents12AndOverUBAllowance = 350
+ const depedentsUnder12UBAllowance = 175
+ const maxWholeFamilyCivilianUBAllowance = 2000
+ const studentTravelMaxAllowance = 350
+ ubAllowance := 0
+
+ if typeOfOrder == string(internalmessages.OrdersTypeSTUDENTTRAVEL) {
+ ubAllowance = studentTravelMaxAllowance
+ } else if orderPayGrade == string(internalmessages.OrderPayGradeCIVILIANEMPLOYEE) && dependentsAreAuthorized && underTwelveDependents == 0 && twelveAndOverDependents == 0 {
+ ubAllowance = civilianBaseUBAllowance
+ } else if orderPayGrade == string(internalmessages.OrderPayGradeCIVILIANEMPLOYEE) && dependentsAreAuthorized && (underTwelveDependents > 0 || twelveAndOverDependents > 0) {
+ ubAllowance = civilianBaseUBAllowance
+ // for each dependent 12 and older, add an additional 350 lbs to the civilian's baggage allowance
+ ubAllowance += twelveAndOverDependents * dependents12AndOverUBAllowance
+ // for each dependent under 12, add an additional 175 lbs to the civilian's baggage allowance
+ ubAllowance += underTwelveDependents * depedentsUnder12UBAllowance
+ // max allowance of 2,000 lbs for entire family
+ if ubAllowance > maxWholeFamilyCivilianUBAllowance {
+ ubAllowance = maxWholeFamilyCivilianUBAllowance
+ }
+ } else {
+ if typeOfOrder == string(internalmessages.OrdersTypeLOCALMOVE) {
+ // no UB allowance for local moves
+ return 0, nil
+ } else if typeOfOrder != string(internalmessages.OrdersTypeTEMPORARYDUTY) {
+ // all order types other than temporary duty are treated as permanent change of station types for the lookup
+ typeOfOrder = string(internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ }
+ // space force members entitled to the same allowance as air force members
+ if branchOfService == AffiliationSPACEFORCE.String() {
+ branchOfService = AffiliationAIRFORCE.String()
+ }
+ // e9 special senior enlisted members entitled to the same allowance as e9 members
+ if orderPayGrade == string(ServiceMemberGradeE9SPECIALSENIORENLISTED) {
+ orderPayGrade = string(ServiceMemberGradeE9)
+ }
+
+ var baseUBAllowance UBAllowances
+ err := appCtx.DB().Where("branch = ? AND grade = ? AND orders_type = ? AND dependents_authorized = ? AND accompanied_tour = ?", branchOfService, orderPayGrade, typeOfOrder, dependentsAreAuthorized, isAnAccompaniedTour).First(&baseUBAllowance)
+ if err != nil {
+ if errors.Cause(err).Error() == RecordNotFoundErrorString {
+ message := fmt.Sprintf("No UB allowance entry found in ub_allowances table for branch: %s, grade: %s, orders_type: %s, dependents_authorized: %t, accompanied_tour: %t.", branchOfService, orderPayGrade, typeOfOrder, dependentsAreAuthorized, isAnAccompaniedTour)
+ appCtx.Logger().Info(message)
+ return 0, nil
+ }
+ return 0, err
+ }
+ if baseUBAllowance.UBAllowance != nil {
+ ubAllowance = *baseUBAllowance.UBAllowance
+ return ubAllowance, nil
+ } else {
+ return 0, nil
+ }
+ }
+ return ubAllowance, nil
+ } else {
+ appCtx.Logger().Info("No OCONUS duty location found for orders, no UB allowance calculated as part of order entitlement.")
+ return 0, nil
+ }
+}
+
+// WeightAllotment represents the weights allotted for a rank
+type WeightAllotment struct {
+ TotalWeightSelf int
+ TotalWeightSelfPlusDependents int
+ ProGearWeight int
+ ProGearWeightSpouse int
+ UnaccompaniedBaggageAllowance int
+}
diff --git a/pkg/models/ghc_entitlements_test.go b/pkg/models/ghc_entitlements_test.go
index d5e56ca96b7..f3cd227f2f1 100644
--- a/pkg/models/ghc_entitlements_test.go
+++ b/pkg/models/ghc_entitlements_test.go
@@ -1,7 +1,6 @@
package models_test
import (
- "github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/models"
)
@@ -14,23 +13,6 @@ func (suite *ModelSuite) TestAuthorizedWeightWhenExistsInDB() {
suite.Equal(entitlement.DBAuthorizedWeight, entitlement.AuthorizedWeight())
}
-func (suite *ModelSuite) TestAuthorizedWeightWhenNotInDBAndHaveWeightAllotment() {
- suite.Run("with no dependents authorized, TotalWeightSelf is AuthorizedWeight", func() {
- entitlement := models.Entitlement{}
- entitlement.SetWeightAllotment("E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
-
- suite.Equal(entitlement.WeightAllotment().TotalWeightSelf, *entitlement.AuthorizedWeight())
- })
-
- suite.Run("with dependents authorized, TotalWeightSelfPlusDependents is AuthorizedWeight", func() {
- dependentsAuthorized := true
- entitlement := models.Entitlement{DependentsAuthorized: &dependentsAuthorized}
- entitlement.SetWeightAllotment("E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
-
- suite.Equal(entitlement.WeightAllotment().TotalWeightSelfPlusDependents, *entitlement.AuthorizedWeight())
- })
-}
-
func (suite *ModelSuite) TestProGearAndProGearSpouseWeight() {
suite.Run("no validation errors for ProGearWeight and ProGearSpouseWeight", func() {
entitlement := models.Entitlement{
diff --git a/pkg/models/hhg_allowance.go b/pkg/models/hhg_allowance.go
new file mode 100644
index 00000000000..d9c3972637f
--- /dev/null
+++ b/pkg/models/hhg_allowance.go
@@ -0,0 +1,43 @@
+package models
+
+import (
+ "time"
+
+ "github.com/gobuffalo/pop/v6"
+ "github.com/gobuffalo/validate/v3"
+ "github.com/gobuffalo/validate/v3/validators"
+ "github.com/gofrs/uuid"
+)
+
+// HHGAllowance the allowance in weights for a given pay grade
+type HHGAllowance struct {
+ ID uuid.UUID `json:"id" db:"id"`
+ PayGradeID uuid.UUID `json:"pay_grade_id" db:"pay_grade_id"`
+ PayGrade PayGrade `belongs_to:"pay_grades" fk_id:"pay_grade_id"`
+ TotalWeightSelf int `json:"total_weight_self" db:"total_weight_self"`
+ TotalWeightSelfPlusDependents int `json:"total_weight_self_plus_dependents" db:"total_weight_self_plus_dependents"`
+ ProGearWeight int `json:"pro_gear_weight" db:"pro_gear_weight"`
+ ProGearWeightSpouse int `json:"pro_gear_weight_spouse" db:"pro_gear_weight_spouse"`
+ CreatedAt time.Time `json:"created_at" db:"created_at"`
+ UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
+}
+
+// Validate gets run every time you call a "pop.Validate*" method
+func (h HHGAllowance) Validate(_ *pop.Connection) (*validate.Errors, error) {
+ return validate.Validate(
+ &validators.UUIDIsPresent{Name: "PayGradeID", Field: h.PayGradeID},
+ // Make sure we don't somehow get a negative value
+ &validators.IntIsGreaterThan{Name: "TotalWeightSelf", Field: h.TotalWeightSelf, Compared: -1},
+ &validators.IntIsGreaterThan{Name: "TotalWeightSelfPlusDependents", Field: h.TotalWeightSelfPlusDependents, Compared: -1},
+ &validators.IntIsGreaterThan{Name: "ProGearWeight", Field: h.ProGearWeight, Compared: -1},
+ &validators.IntIsGreaterThan{Name: "ProGearWeightSpouse", Field: h.ProGearWeightSpouse, Compared: -1},
+ ), nil
+}
+
+// HHGAllowances is a slice of HHGAllowance
+type HHGAllowances []HHGAllowance
+
+// TableName overrides the table name used by Pop.
+func (h HHGAllowance) TableName() string {
+ return "hhg_allowances"
+}
diff --git a/pkg/models/hhg_allowance_test.go b/pkg/models/hhg_allowance_test.go
new file mode 100644
index 00000000000..f3df8346a95
--- /dev/null
+++ b/pkg/models/hhg_allowance_test.go
@@ -0,0 +1,53 @@
+package models_test
+
+import (
+ "github.com/gofrs/uuid"
+
+ m "github.com/transcom/mymove/pkg/models"
+)
+
+func (suite *ModelSuite) TestBasicHHGAllowanceInstantiation() {
+
+ newHHGAllowance := &m.HHGAllowance{
+ PayGradeID: uuid.Must(uuid.NewV4()),
+ TotalWeightSelf: 5000,
+ TotalWeightSelfPlusDependents: 8000,
+ ProGearWeight: 2000,
+ ProGearWeightSpouse: 500,
+ }
+
+ verrs, err := newHHGAllowance.Validate(nil)
+
+ suite.NoError(err)
+ suite.False(verrs.HasAny(), "Error validating model")
+}
+
+func (suite *ModelSuite) TestEmptyHHGAllowanceInstantiation() {
+ newHHGAllowance := m.HHGAllowance{}
+
+ expErrors := map[string][]string{
+ "pay_grade_id": {"PayGradeID can not be blank."},
+ }
+
+ suite.verifyValidationErrors(&newHHGAllowance, expErrors)
+}
+
+// Test validation fields that pass when empty but fail with faulty values
+func (suite *ModelSuite) TestFaultyHHGAllowanceInstantiation() {
+ newHHGAllowance := m.HHGAllowance{
+ PayGradeID: uuid.Must(uuid.NewV4()),
+ TotalWeightSelf: -1,
+ TotalWeightSelfPlusDependents: -1,
+ ProGearWeight: -1,
+ ProGearWeightSpouse: -1,
+ }
+
+ expErrors := map[string][]string{
+ "total_weight_self": {"-1 is not greater than -1."},
+ "total_weight_self_plus_dependents": {"-1 is not greater than -1."},
+ "pro_gear_weight": {"-1 is not greater than -1."},
+ "pro_gear_weight_spouse": {"-1 is not greater than -1."},
+ }
+
+ suite.verifyValidationErrors(&newHHGAllowance, expErrors)
+}
diff --git a/pkg/models/order.go b/pkg/models/order.go
index 84d5c215349..476b96b1d43 100644
--- a/pkg/models/order.go
+++ b/pkg/models/order.go
@@ -1,6 +1,9 @@
package models
import (
+ "bytes"
+ "encoding/json"
+ "fmt"
"sort"
"time"
@@ -185,6 +188,18 @@ func (o *Order) Cancel() error {
return nil
}
+var ordersTypeToAllotmentAppParamName = map[internalmessages.OrdersType]string{
+ internalmessages.OrdersTypeSTUDENTTRAVEL: "studentTravelHhgAllowance",
+}
+
+// Helper func to enforce strict unmarshal of application param values into a given interface
+func strictUnmarshal(data []byte, v interface{}) error {
+ decoder := json.NewDecoder(bytes.NewReader(data))
+ // Fail on unknown fields
+ decoder.DisallowUnknownFields()
+ return decoder.Decode(v)
+}
+
// FetchOrderForUser returns orders only if it is allowed for the given user to access those orders.
func FetchOrderForUser(db *pop.Connection, session *auth.Session, id uuid.UUID) (Order, error) {
var order Order
@@ -209,6 +224,52 @@ func FetchOrderForUser(db *pop.Connection, session *auth.Session, id uuid.UUID)
return Order{}, err
}
+ // Conduct allotment lookup
+ if order.Entitlement != nil && order.Grade != nil {
+ switch order.OrdersType {
+ case internalmessages.OrdersTypeSTUDENTTRAVEL:
+ // We currently store orders allotment overrides as an application parameter
+ // as it is a current one-off use case introduced by E-06189
+ var jsonData json.RawMessage
+ if paramName, ok := ordersTypeToAllotmentAppParamName[order.OrdersType]; ok {
+ err := db.RawQuery(`
+ SELECT parameter_json
+ FROM application_parameters
+ WHERE parameter_name = $1
+ `, paramName).First(&jsonData)
+
+ if err != nil {
+ return Order{}, fmt.Errorf("failed to fetch weight allotment for orders type %s: %w", order.OrdersType, err)
+ }
+
+ // Convert the JSON data to the WeightAllotment struct
+ err = strictUnmarshal(jsonData, &order.Entitlement.WeightAllotted)
+ if err != nil {
+ return Order{}, fmt.Errorf("failed to parse weight allotment JSON for orders type %s: %w", order.OrdersType, err)
+ }
+ }
+ default:
+ var hhgAllowance HHGAllowance
+ err = db.RawQuery(`
+ SELECT hhg_allowances.*
+ FROM hhg_allowances
+ INNER JOIN pay_grades ON hhg_allowances.pay_grade_id = pay_grades.id
+ WHERE pay_grades.grade = $1
+ LIMIT 1
+ `, order.Grade).First(&hhgAllowance)
+ if err != nil {
+ return Order{}, fmt.Errorf("failed to parse weight allotment JSON for orders type %s: %w", order.OrdersType, err)
+ }
+ order.Entitlement.WeightAllotted = &WeightAllotment{
+ TotalWeightSelf: hhgAllowance.TotalWeightSelf,
+ TotalWeightSelfPlusDependents: hhgAllowance.TotalWeightSelfPlusDependents,
+ ProGearWeight: hhgAllowance.ProGearWeight,
+ ProGearWeightSpouse: hhgAllowance.ProGearWeightSpouse,
+ }
+
+ }
+ }
+
// TODO: Handle case where more than one user is authorized to modify orders
if session.IsMilApp() && order.ServiceMember.ID != session.ServiceMemberID {
return Order{}, ErrFetchForbidden
diff --git a/pkg/models/order_test.go b/pkg/models/order_test.go
index 6ef09fe7598..b275f131753 100644
--- a/pkg/models/order_test.go
+++ b/pkg/models/order_test.go
@@ -1,6 +1,7 @@
package models_test
import (
+ "encoding/json"
"time"
"github.com/gofrs/uuid"
@@ -115,6 +116,22 @@ func (suite *ModelSuite) TestTacFormat() {
}
func (suite *ModelSuite) TestFetchOrderForUser() {
+ setupHhgStudentAllowanceParameter := func() {
+ paramJSON := `{
+ "TotalWeightSelf": 350,
+ "TotalWeightSelfPlusDependents": 350,
+ "ProGearWeight": 0,
+ "ProGearWeightSpouse": 0,
+ "UnaccompaniedBaggageAllowance": 100
+ }`
+ rawMessage := json.RawMessage(paramJSON)
+
+ parameter := models.ApplicationParameters{
+ ParameterName: models.StringPointer("studentTravelHhgAllowance"),
+ ParameterJson: &rawMessage,
+ }
+ suite.MustCreate(¶meter)
+ }
suite.Run("successful fetch by authorized user", func() {
order := factory.BuildOrder(suite.DB(), nil, nil)
@@ -139,6 +156,35 @@ func (suite *ModelSuite) TestFetchOrderForUser() {
suite.Equal(order.UploadedOrdersID, goodOrder.UploadedOrdersID)
})
+ suite.Run("retrieves student entitlement properly for user", func() {
+ setupHhgStudentAllowanceParameter()
+ order := factory.BuildOrder(suite.DB(), []factory.Customization{
+ {
+ Model: models.Order{
+ OrdersType: internalmessages.OrdersTypeSTUDENTTRAVEL,
+ },
+ },
+ }, nil)
+
+ // User is authorized to fetch order
+ session := &auth.Session{
+ ApplicationName: auth.MilApp,
+ UserID: order.ServiceMember.UserID,
+ ServiceMemberID: order.ServiceMemberID,
+ }
+ goodOrder, err := m.FetchOrderForUser(suite.DB(), session, order.ID)
+
+ suite.NoError(err)
+ suite.FatalNotNil(goodOrder.Entitlement)
+ suite.FatalNotNil(goodOrder.Entitlement.WeightAllotted)
+ suite.Equal(goodOrder.Entitlement.WeightAllotted.TotalWeightSelf, 350)
+ suite.Equal(goodOrder.Entitlement.WeightAllotted.TotalWeightSelfPlusDependents, 350)
+ suite.Equal(goodOrder.Entitlement.WeightAllotted.ProGearWeight, 0)
+ suite.Equal(goodOrder.Entitlement.WeightAllotted.ProGearWeightSpouse, 0)
+ suite.Equal(goodOrder.Entitlement.WeightAllotted.UnaccompaniedBaggageAllowance, 100)
+
+ })
+
suite.Run("check for closeout office", func() {
closeoutOffice := factory.BuildTransportationOffice(suite.DB(), nil, nil)
move := factory.BuildMove(suite.DB(), []factory.Customization{
diff --git a/pkg/models/pay_grade.go b/pkg/models/pay_grade.go
new file mode 100644
index 00000000000..a427e0d7dcf
--- /dev/null
+++ b/pkg/models/pay_grade.go
@@ -0,0 +1,29 @@
+package models
+
+import (
+ "time"
+
+ "github.com/gobuffalo/pop/v6"
+ "github.com/gobuffalo/validate/v3"
+ "github.com/gobuffalo/validate/v3/validators"
+ "github.com/gofrs/uuid"
+)
+
+// PayGrade represents a customer's pay grade (Including civilian)
+type PayGrade struct {
+ ID uuid.UUID `json:"id" db:"id"`
+ Grade string `json:"grade" db:"grade"`
+ GradeDescription *string `json:"grade_description" db:"grade_description"`
+ CreatedAt time.Time `json:"created_at" db:"created_at"`
+ UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
+}
+
+// Validate gets run every time you call a "pop.Validate*" method
+func (pg PayGrade) Validate(_ *pop.Connection) (*validate.Errors, error) {
+ return validate.Validate(
+ &validators.StringIsPresent{Name: "Grade", Field: pg.Grade},
+ ), nil
+}
+
+// PayGrades is a slice of PayGrade
+type PayGrades []PayGrade
diff --git a/pkg/models/pay_grade_test.go b/pkg/models/pay_grade_test.go
new file mode 100644
index 00000000000..3a5cf233bc2
--- /dev/null
+++ b/pkg/models/pay_grade_test.go
@@ -0,0 +1,25 @@
+package models_test
+
+import (
+ m "github.com/transcom/mymove/pkg/models"
+)
+
+func (suite *ModelSuite) TestBasicPayGradeInstantiation() {
+ newPayGrade := &m.PayGrade{
+ Grade: "NewGrade",
+ }
+
+ verrs, err := newPayGrade.Validate(nil)
+
+ suite.NoError(err)
+ suite.False(verrs.HasAny(), "Error validating model")
+}
+
+func (suite *ModelSuite) TestEmptyPayGradeInstantiation() {
+ newPayGrade := m.PayGrade{}
+
+ expErrors := map[string][]string{
+ "grade": {"Grade can not be blank."},
+ }
+ suite.verifyValidationErrors(&newPayGrade, expErrors)
+}
diff --git a/pkg/models/queue_test.go b/pkg/models/queue_test.go
deleted file mode 100644
index 18d2e3b90c0..00000000000
--- a/pkg/models/queue_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package models_test
-
-import (
- "github.com/transcom/mymove/pkg/factory"
- m "github.com/transcom/mymove/pkg/models"
-)
-
-func (suite *ModelSuite) TestCreateMoveWithPPMShow() {
-
- factory.BuildMoveWithPPMShipment(suite.DB(), nil, nil)
-
- moves, moveErrs := m.GetMoveQueueItems(suite.DB(), "all")
- suite.Nil(moveErrs)
- suite.Len(moves, 1)
-}
-
-func (suite *ModelSuite) TestCreateMoveWithPPMNoShow() {
- moveTemplate := m.Move{
- Show: m.BoolPointer(false),
- }
- factory.BuildMoveWithPPMShipment(suite.DB(), []factory.Customization{
- {
- Model: moveTemplate,
- },
- }, nil)
-
- moves, moveErrs := m.GetMoveQueueItems(suite.DB(), "all")
- suite.Nil(moveErrs)
- suite.Empty(moves)
-
-}
-
-func (suite *ModelSuite) TestCreateNewMoveWithNoPPMShow() {
- orders := factory.BuildOrder(suite.DB(), nil, nil)
- factory.FetchOrBuildDefaultContractor(suite.DB(), nil, nil)
- office := factory.BuildTransportationOffice(suite.DB(), nil, nil)
-
- moveOptions := m.MoveOptions{
- Show: m.BoolPointer(true),
- CounselingOfficeID: &office.ID,
- }
- _, verrs, err := orders.CreateNewMove(suite.DB(), moveOptions)
- suite.NoError(err)
- suite.False(verrs.HasAny(), "failed to validate move")
-
- moves, moveErrs := m.GetMoveQueueItems(suite.DB(), "all")
- suite.Nil(moveErrs)
- suite.Empty(moves)
-}
-
-func (suite *ModelSuite) TestQueueNotFound() {
- moves, moveErrs := m.GetMoveQueueItems(suite.DB(), "queue_not_found")
- suite.Equal(m.ErrFetchNotFound, moveErrs, "Expected not to find move queue items")
- suite.Empty(moves)
-}
diff --git a/pkg/notifications/move_submitted.go b/pkg/notifications/move_submitted.go
index d9cc1a26431..e553ce2e480 100644
--- a/pkg/notifications/move_submitted.go
+++ b/pkg/notifications/move_submitted.go
@@ -2,6 +2,7 @@ package notifications
import (
"bytes"
+ "errors"
"fmt"
html "html/template"
text "text/template"
@@ -53,6 +54,15 @@ func (m MoveSubmitted) emails(appCtx appcontext.AppContext) ([]emailContent, err
return emails, err
}
+ // Nil check here. Previously weight allotments were hard coded and a lookup was placed here.
+ // Since allotments are now stored in the database, to avoid an import circle we enhance the
+ // "FetchOrderForUser" to return the allotment, preventing any need for addtional lookup or db querying.
+ if orders.Entitlement == nil || orders.Entitlement.WeightAllotted == nil {
+ errMsg := "WeightAllotted is nil during move email generation. Ensure orders fetch includes an entitlement join and the correct pay grade exists"
+ appCtx.Logger().Error(errMsg, zap.String("orderID", orders.ID.String()))
+ return nil, errors.New(errMsg)
+ }
+
destinationAddress := orders.NewDutyLocation.Name
isSeparateeRetiree := orders.OrdersType == internalmessages.OrdersTypeRETIREMENT || orders.OrdersType == internalmessages.OrdersTypeSEPARATION
if isSeparateeRetiree && len(move.MTOShipments) > 0 {
@@ -90,15 +100,14 @@ func (m MoveSubmitted) emails(appCtx appcontext.AppContext) ([]emailContent, err
originDutyLocationName = &originDutyLocation.Name
}
- totalEntitlement := models.GetWeightAllotment(*orders.Grade, orders.OrdersType)
unaccompaniedBaggageAllowance, err := models.GetUBWeightAllowance(appCtx, originDutyLocation.Address.IsOconus, orders.NewDutyLocation.Address.IsOconus, orders.ServiceMember.Affiliation, orders.Grade, &orders.OrdersType, orders.Entitlement.DependentsAuthorized, orders.Entitlement.AccompaniedTour, orders.Entitlement.DependentsUnderTwelve, orders.Entitlement.DependentsTwelveAndOver)
if err == nil {
- totalEntitlement.UnaccompaniedBaggageAllowance = unaccompaniedBaggageAllowance
+ orders.Entitlement.WeightAllotted.UnaccompaniedBaggageAllowance = unaccompaniedBaggageAllowance
}
- weight := totalEntitlement.TotalWeightSelf
+ weight := orders.Entitlement.WeightAllotted.TotalWeightSelf
if orders.HasDependents {
- weight = totalEntitlement.TotalWeightSelfPlusDependents
+ weight = orders.Entitlement.WeightAllotted.TotalWeightSelfPlusDependents
}
if serviceMember.PersonalEmail == nil {
diff --git a/pkg/services/entitlements.go b/pkg/services/entitlements.go
new file mode 100644
index 00000000000..58b8ccc09fd
--- /dev/null
+++ b/pkg/services/entitlements.go
@@ -0,0 +1,30 @@
+package services
+
+import (
+ "github.com/transcom/mymove/pkg/appcontext"
+ "github.com/transcom/mymove/pkg/gen/internalmessages"
+ "github.com/transcom/mymove/pkg/models"
+)
+
+// The weight allotment fetcher interface helps identify weight allotments (allowances) for a given grade
+//
+//go:generate mockery --name WeightAllotmentFetcher
+type WeightAllotmentFetcher interface {
+ GetWeightAllotment(appCtx appcontext.AppContext, grade string, ordersType internalmessages.OrdersType) (models.WeightAllotment, error)
+ GetAllWeightAllotments(appCtx appcontext.AppContext) (map[internalmessages.OrderPayGrade]models.WeightAllotment, error)
+ GetWeightAllotmentByOrdersType(appCtx appcontext.AppContext, ordersType internalmessages.OrdersType) (models.WeightAllotment, error)
+}
+
+// The weight restrictor interface helps apply weight restrictions to entitlements
+//
+//go:generate mockery --name WeightRestrictor
+type WeightRestrictor interface {
+ ApplyWeightRestrictionToEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, weightRestriction int, eTag string) (*models.Entitlement, error)
+ RemoveWeightRestrictionFromEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, eTag string) (*models.Entitlement, error)
+}
+
+// The weight allotment saver helps apply weight restrictions to entitlements
+//
+//go:generate mockery --name WeightRestrictor
+type WeightAllotmentSaver interface {
+}
diff --git a/pkg/services/entitlements/entitlements_service_test.go b/pkg/services/entitlements/entitlements_service_test.go
new file mode 100644
index 00000000000..241ebd258cd
--- /dev/null
+++ b/pkg/services/entitlements/entitlements_service_test.go
@@ -0,0 +1,27 @@
+package entitlements
+
+import (
+ "testing"
+
+ "github.com/spf13/afero"
+ "github.com/stretchr/testify/suite"
+
+ "github.com/transcom/mymove/pkg/testingsuite"
+)
+
+// EntitlementsServiceSuite is a suite for testing entitlement service objects
+type EntitlementsServiceSuite struct {
+ *testingsuite.PopTestSuite
+ fs *afero.Afero
+}
+
+func TestEntitlementsServiceSuite(t *testing.T) {
+ var f = afero.NewMemMapFs()
+ file := &afero.Afero{Fs: f}
+ ts := &EntitlementsServiceSuite{
+ PopTestSuite: testingsuite.NewPopTestSuite(testingsuite.CurrentPackage(), testingsuite.WithPerTestTransaction()),
+ fs: file,
+ }
+ suite.Run(t, ts)
+ ts.PopTestSuite.TearDown()
+}
diff --git a/pkg/services/entitlements/weight_allotment_fetcher.go b/pkg/services/entitlements/weight_allotment_fetcher.go
new file mode 100644
index 00000000000..718a0e30169
--- /dev/null
+++ b/pkg/services/entitlements/weight_allotment_fetcher.go
@@ -0,0 +1,122 @@
+package entitlements
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+
+ "github.com/transcom/mymove/pkg/appcontext"
+ "github.com/transcom/mymove/pkg/apperror"
+ "github.com/transcom/mymove/pkg/gen/internalmessages"
+ "github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services"
+)
+
+type weightAllotmentFetcher struct {
+}
+
+// NewWeightAllotmentFetcher returns a new weight allotment fetcher
+func NewWeightAllotmentFetcher() services.WeightAllotmentFetcher {
+ return &weightAllotmentFetcher{}
+}
+
+func (waf *weightAllotmentFetcher) GetWeightAllotment(appCtx appcontext.AppContext, grade string, ordersType internalmessages.OrdersType) (models.WeightAllotment, error) {
+ // Check order allotment first
+ if ordersType == internalmessages.OrdersTypeSTUDENTTRAVEL { // currently only applies to student travel order that limits overall authorized weight
+ entitlement, err := waf.GetWeightAllotmentByOrdersType(appCtx, ordersType)
+ if err != nil {
+ return models.WeightAllotment{}, err
+ }
+ return entitlement, nil
+ }
+
+ // Continue if the orders type is not student travel
+ var hhgAllowance models.HHGAllowance
+ err := appCtx.DB().
+ RawQuery(`
+ SELECT hhg_allowances.*
+ FROM hhg_allowances
+ INNER JOIN pay_grades ON hhg_allowances.pay_grade_id = pay_grades.id
+ WHERE pay_grades.grade = $1
+ LIMIT 1
+ `, grade).
+ First(&hhgAllowance)
+ if err != nil {
+ return models.WeightAllotment{}, apperror.NewQueryError("HHGAllowance", err, fmt.Sprintf("Error retrieving HHG allowance for grade: %s", grade))
+ }
+
+ // Convert HHGAllowance to WeightAllotment
+ weightAllotment := models.WeightAllotment{
+ TotalWeightSelf: hhgAllowance.TotalWeightSelf,
+ TotalWeightSelfPlusDependents: hhgAllowance.TotalWeightSelfPlusDependents,
+ ProGearWeight: hhgAllowance.ProGearWeight,
+ ProGearWeightSpouse: hhgAllowance.ProGearWeightSpouse,
+ }
+
+ return weightAllotment, nil
+}
+
+var ordersTypeToAllotmentAppParamName = map[internalmessages.OrdersType]string{
+ internalmessages.OrdersTypeSTUDENTTRAVEL: "studentTravelHhgAllowance",
+}
+
+// Helper func to enforce strict unmarshal of application param values into a given interface
+func strictUnmarshal(data []byte, v interface{}) error {
+ decoder := json.NewDecoder(bytes.NewReader(data))
+ // Fail on unknown fields
+ decoder.DisallowUnknownFields()
+ return decoder.Decode(v)
+}
+
+func (waf *weightAllotmentFetcher) GetWeightAllotmentByOrdersType(appCtx appcontext.AppContext, ordersType internalmessages.OrdersType) (models.WeightAllotment, error) {
+ if paramName, ok := ordersTypeToAllotmentAppParamName[ordersType]; ok {
+ // We currently store orders allotment overrides as an application parameter
+ // as it is a current one-off use case introduced by E-06189
+ var jsonData json.RawMessage
+ err := appCtx.DB().RawQuery(`
+ SELECT parameter_json
+ FROM application_parameters
+ WHERE parameter_name = $1
+ `, paramName).First(&jsonData)
+
+ if err != nil {
+ return models.WeightAllotment{}, fmt.Errorf("failed to fetch weight allotment for orders type %s: %w", ordersType, err)
+ }
+
+ // Convert the JSON data to the WeightAllotment struct
+ var weightAllotment models.WeightAllotment
+ err = strictUnmarshal(jsonData, &weightAllotment)
+ if err != nil {
+ return models.WeightAllotment{}, fmt.Errorf("failed to parse weight allotment JSON for orders type %s: %w", ordersType, err)
+ }
+
+ return weightAllotment, nil
+ }
+ return models.WeightAllotment{}, fmt.Errorf("no entitlement found for orders type %s", ordersType)
+}
+
+func (waf *weightAllotmentFetcher) GetAllWeightAllotments(appCtx appcontext.AppContext) (map[internalmessages.OrderPayGrade]models.WeightAllotment, error) {
+ var hhgAllowances models.HHGAllowances
+ err := appCtx.DB().
+ Eager("PayGrade").
+ All(&hhgAllowances)
+ if err != nil {
+ return nil, apperror.NewQueryError("HHGAllowances", err, "Error retrieving all HHG allowances")
+ }
+
+ weightAllotments := make(map[internalmessages.OrderPayGrade]models.WeightAllotment)
+
+ for _, hhgAllowance := range hhgAllowances {
+ // Convert HHGAllowance to WeightAllotment
+ weightAllotment := models.WeightAllotment{
+ TotalWeightSelf: hhgAllowance.TotalWeightSelf,
+ TotalWeightSelfPlusDependents: hhgAllowance.TotalWeightSelfPlusDependents,
+ ProGearWeight: hhgAllowance.ProGearWeight,
+ ProGearWeightSpouse: hhgAllowance.ProGearWeightSpouse,
+ }
+
+ grade := internalmessages.OrderPayGrade(hhgAllowance.PayGrade.Grade)
+ weightAllotments[grade] = weightAllotment
+ }
+ return weightAllotments, nil
+}
diff --git a/pkg/services/entitlements/weight_allotment_fetcher_test.go b/pkg/services/entitlements/weight_allotment_fetcher_test.go
new file mode 100644
index 00000000000..43330be5c09
--- /dev/null
+++ b/pkg/services/entitlements/weight_allotment_fetcher_test.go
@@ -0,0 +1,128 @@
+package entitlements
+
+import (
+ "encoding/json"
+
+ "github.com/transcom/mymove/pkg/apperror"
+ "github.com/transcom/mymove/pkg/gen/internalmessages"
+ "github.com/transcom/mymove/pkg/models"
+)
+
+func (suite *EntitlementsServiceSuite) TestGetWeightAllotment() {
+ suite.Run("If a weight allotment is fetched by grade, it should be returned", func() {
+ fetcher := NewWeightAllotmentFetcher()
+
+ allotment, err := fetcher.GetWeightAllotment(suite.AppContextForTest(), "E_1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+
+ suite.NoError(err)
+ suite.NotEmpty(allotment)
+ })
+
+ suite.Run("If pay grade does not exist, return an error", func() {
+ fetcher := NewWeightAllotmentFetcher()
+
+ allotment, err := fetcher.GetWeightAllotment(suite.AppContextForTest(), "X-1", internalmessages.OrdersTypePERMANENTCHANGEOFSTATION)
+ suite.Error(err)
+ suite.IsType(apperror.QueryError{}, err)
+ suite.Empty(allotment)
+ })
+}
+
+func (suite *EntitlementsServiceSuite) TestGetAllWeightAllotments() {
+ suite.Run("Successfully fetch all weight allotments", func() {
+ fetcher := NewWeightAllotmentFetcher()
+
+ allotments, err := fetcher.GetAllWeightAllotments(suite.AppContextForTest())
+ suite.NoError(err)
+ suite.Greater(len(allotments), 0)
+ })
+}
+
+func (suite *EntitlementsServiceSuite) TestGetWeightAllotmentByOrdersType() {
+ setupHhgStudentAllowanceParameter := func() {
+ paramJSON := `{
+ "TotalWeightSelf": 350,
+ "TotalWeightSelfPlusDependents": 350,
+ "ProGearWeight": 0,
+ "ProGearWeightSpouse": 0,
+ "UnaccompaniedBaggageAllowance": 100
+ }`
+ rawMessage := json.RawMessage(paramJSON)
+
+ parameter := models.ApplicationParameters{
+ ParameterName: models.StringPointer("studentTravelHhgAllowance"),
+ ParameterJson: &rawMessage,
+ }
+ suite.MustCreate(¶meter)
+ }
+
+ suite.Run("Successfully fetch student travel allotment from application_parameters", func() {
+ setupHhgStudentAllowanceParameter()
+ fetcher := NewWeightAllotmentFetcher()
+
+ allotment, err := fetcher.GetWeightAllotment(
+ suite.AppContextForTest(),
+ "E-1",
+ internalmessages.OrdersTypeSTUDENTTRAVEL,
+ )
+
+ suite.NoError(err)
+ suite.Equal(350, allotment.TotalWeightSelf)
+ suite.Equal(350, allotment.TotalWeightSelfPlusDependents)
+ suite.Equal(0, allotment.ProGearWeight)
+ suite.Equal(0, allotment.ProGearWeightSpouse)
+ suite.Equal(100, allotment.UnaccompaniedBaggageAllowance)
+ })
+
+ suite.Run("Returns an error if json does not match allotment from db", func() {
+ // Proper JSON but not proper target struct
+ faultyParamJSON := `{
+ "TotalWeight": 350,
+ "TotalWeightPlusDependents": 350,
+ "ProGear": 0,
+ "ProGearSpouse": 0,
+ "Allowance": 100
+ }`
+ rawMessage := json.RawMessage(faultyParamJSON)
+
+ parameter := models.ApplicationParameters{
+ ParameterName: models.StringPointer("studentTravelHhgAllowance"),
+ ParameterJson: &rawMessage,
+ }
+ suite.MustCreate(¶meter)
+
+ fetcher := NewWeightAllotmentFetcher()
+ _, err := fetcher.GetWeightAllotmentByOrdersType(
+ suite.AppContextForTest(),
+ internalmessages.OrdersTypeSTUDENTTRAVEL,
+ )
+
+ suite.Error(err)
+ suite.Contains(err.Error(), "failed to parse weight allotment JSON for orders type")
+
+ })
+
+ suite.Run("Returns an error if no application_parameters entry exists for student travel", func() {
+ // Don’t create the parameter this time for the student travel
+ fetcher := NewWeightAllotmentFetcher()
+ _, err := fetcher.GetWeightAllotment(
+ suite.AppContextForTest(),
+ "E-1",
+ internalmessages.OrdersTypeSTUDENTTRAVEL,
+ )
+
+ suite.Error(err)
+ suite.Contains(err.Error(), "failed to fetch weight allotment for orders type STUDENT_TRAVEL: sql: no rows in result set")
+ })
+
+ suite.Run("Returns an error if the orders type is not in the ordersTypeToAllotmentAppParamName map", func() {
+ fetcher := NewWeightAllotmentFetcher()
+ _, err := fetcher.GetWeightAllotmentByOrdersType(
+ suite.AppContextForTest(),
+ internalmessages.OrdersTypeSEPARATION,
+ )
+
+ suite.Error(err)
+ suite.Contains(err.Error(), "no entitlement found for orders type SEPARATION")
+ })
+}
diff --git a/pkg/services/entitlements/weight_restrictor.go b/pkg/services/entitlements/weight_restrictor.go
new file mode 100644
index 00000000000..a8255aa51cf
--- /dev/null
+++ b/pkg/services/entitlements/weight_restrictor.go
@@ -0,0 +1,100 @@
+package entitlements
+
+import (
+ "fmt"
+
+ "github.com/pkg/errors"
+
+ "github.com/transcom/mymove/pkg/appcontext"
+ "github.com/transcom/mymove/pkg/apperror"
+ "github.com/transcom/mymove/pkg/etag"
+ "github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services"
+)
+
+type weightRestrictor struct {
+}
+
+func NewWeightRestrictor() services.WeightRestrictor {
+ return &weightRestrictor{}
+}
+
+func (wr *weightRestrictor) ApplyWeightRestrictionToEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, weightRestriction int, eTag string) (*models.Entitlement, error) {
+ // First, fetch the latest version of the entitlement for etag check
+ var originalEntitlement models.Entitlement
+ err := appCtx.DB().Find(&originalEntitlement, entitlement.ID)
+ if err != nil {
+ return nil, apperror.NewQueryError("Entitlements", err, "error fetching entitlement")
+ }
+
+ // verify ETag
+ if etag.GenerateEtag(originalEntitlement.UpdatedAt) != eTag {
+ return nil, apperror.NewPreconditionFailedError(originalEntitlement.ID, nil)
+ }
+
+ maxHhgAllowance, err := wr.fetchMaxHhgAllowance(appCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ // Don't allow applying a weight restriction above the max allowance, that's silly
+ if weightRestriction > maxHhgAllowance {
+ return nil, apperror.NewInvalidInputError(entitlement.ID,
+ fmt.Errorf("weight restriction %d exceeds max HHG allowance %d", weightRestriction, maxHhgAllowance),
+ nil, "error applying weight restriction")
+ }
+
+ // Update the restriction field
+ originalEntitlement.WeightRestriction = &weightRestriction
+
+ verrs, err := appCtx.DB().ValidateAndUpdate(&originalEntitlement)
+ if err != nil {
+ return nil, apperror.NewQueryError("Entitlements", err, "error updating weight restriction for entitlement")
+ }
+ if verrs != nil && verrs.HasAny() {
+ return nil, apperror.NewInvalidInputError(originalEntitlement.ID, err, verrs, "invalid input while updating entitlement")
+ }
+
+ return &originalEntitlement, nil
+}
+
+func (wr *weightRestrictor) RemoveWeightRestrictionFromEntitlement(appCtx appcontext.AppContext, entitlement models.Entitlement, eTag string) (*models.Entitlement, error) {
+ // Fetch the latest version of the entitlement for etag check
+ var originalEntitlement models.Entitlement
+ err := appCtx.DB().Find(&originalEntitlement, entitlement.ID)
+ if err != nil {
+ if errors.Cause(err).Error() == models.RecordNotFoundErrorString {
+ return nil, apperror.NewNotFoundError(entitlement.ID, "entitlement not found")
+ }
+ return nil, apperror.NewQueryError("Entitlements", err, "error fetching entitlement")
+ }
+
+ // verify ETag
+ if etag.GenerateEtag(originalEntitlement.UpdatedAt) != eTag {
+ return nil, apperror.NewPreconditionFailedError(originalEntitlement.ID, nil)
+ }
+
+ // Update the restriction field
+ originalEntitlement.WeightRestriction = nil
+
+ verrs, err := appCtx.DB().ValidateAndUpdate(&originalEntitlement)
+ if err != nil {
+ return nil, apperror.NewQueryError("Entitlements", err, "error removing weight restriction for entitlement")
+ }
+ if verrs != nil && verrs.HasAny() {
+ return nil, apperror.NewInvalidInputError(originalEntitlement.ID, err, verrs, "invalid input while updating entitlement")
+ }
+
+ return &originalEntitlement, nil
+}
+
+func (wr *weightRestrictor) fetchMaxHhgAllowance(appCtx appcontext.AppContext) (int, error) {
+ var maxHhgAllowance int
+ err := appCtx.DB().
+ RawQuery(`SELECT parameter_value::int FROM application_parameters WHERE parameter_name = 'maxHhgAllowance' LIMIT 1`).
+ First(&maxHhgAllowance)
+ if err != nil {
+ return maxHhgAllowance, apperror.NewQueryError("ApplicationParameters", err, "error fetching max HHG allowance")
+ }
+ return maxHhgAllowance, nil
+}
diff --git a/pkg/services/entitlements/weight_restrictor_test.go b/pkg/services/entitlements/weight_restrictor_test.go
new file mode 100644
index 00000000000..b9b2b534156
--- /dev/null
+++ b/pkg/services/entitlements/weight_restrictor_test.go
@@ -0,0 +1,97 @@
+package entitlements
+
+import (
+ "github.com/gofrs/uuid"
+
+ "github.com/transcom/mymove/pkg/apperror"
+ "github.com/transcom/mymove/pkg/etag"
+ "github.com/transcom/mymove/pkg/models"
+)
+
+func (suite *EntitlementsServiceSuite) TestWeightRestrictor() {
+ setupHhgAllowanceParameter := func() {
+ parameter := models.ApplicationParameters{
+ ParameterName: models.StringPointer("maxHhgAllowance"),
+ ParameterValue: models.StringPointer("18000"),
+ }
+ suite.MustCreate(¶meter)
+ }
+
+ suite.Run("Successfully apply a weight restriction within max allowance", func() {
+ setupHhgAllowanceParameter()
+ // Create a blank entitlement db entry, nothing fancy we just want to update columns
+ entitlement := models.Entitlement{
+ ID: uuid.Must(uuid.NewV4()),
+ }
+ suite.MustCreate(&entitlement)
+
+ // Set a weight restriction within allowance
+ restrictor := NewWeightRestrictor()
+ updatedEntitlement, err := restrictor.ApplyWeightRestrictionToEntitlement(suite.AppContextForTest(), entitlement, 10000, etag.GenerateEtag(entitlement.UpdatedAt))
+ suite.NoError(err)
+ suite.NotNil(updatedEntitlement)
+ suite.NotNil(updatedEntitlement.WeightRestriction)
+ suite.Equal(10000, *updatedEntitlement.WeightRestriction)
+ })
+
+ suite.Run("Attempt to apply restriction above max allowance, expect an error", func() {
+ setupHhgAllowanceParameter()
+ // Create a blank entitlement db entry, nothing fancy we just want to update columns
+ entitlement := models.Entitlement{
+ ID: uuid.Must(uuid.NewV4()),
+ }
+ suite.MustCreate(&entitlement)
+
+ // Set an impossible weight restriction
+ restrictor := NewWeightRestrictor()
+ updatedEntitlement, err := restrictor.ApplyWeightRestrictionToEntitlement(suite.AppContextForTest(), entitlement, 20000, etag.GenerateEtag(entitlement.UpdatedAt))
+ suite.Error(err)
+ suite.Nil(updatedEntitlement)
+ suite.IsType(apperror.InvalidInputError{}, err)
+ })
+
+ suite.Run("No maxHhgAllowance parameter found returns error", func() {
+ entitlement := models.Entitlement{
+ ID: uuid.Must(uuid.NewV4()),
+ }
+ suite.MustCreate(&entitlement)
+
+ restrictor := NewWeightRestrictor()
+ updatedEntitlement, err := restrictor.ApplyWeightRestrictionToEntitlement(suite.AppContextForTest(), entitlement, 10000, etag.GenerateEtag(entitlement.UpdatedAt))
+ suite.Error(err)
+ suite.Nil(updatedEntitlement)
+ suite.IsType(apperror.QueryError{}, err)
+ })
+
+ suite.Run("Successfully remove a weight restriction", func() {
+ setupHhgAllowanceParameter()
+
+ // Create an entitlement with a restriction already applied
+ weightRestriction := 5000
+ entitlement := models.Entitlement{
+ ID: uuid.Must(uuid.NewV4()),
+ WeightRestriction: &weightRestriction,
+ }
+ suite.MustCreate(&entitlement)
+
+ restrictor := NewWeightRestrictor()
+ updatedEntitlement, err := restrictor.RemoveWeightRestrictionFromEntitlement(suite.AppContextForTest(), entitlement, etag.GenerateEtag(entitlement.UpdatedAt))
+ suite.NoError(err)
+ suite.NotNil(updatedEntitlement)
+ suite.Nil(updatedEntitlement.WeightRestriction)
+ })
+
+ suite.Run("Fails on removing a weight restriction for an entitlement that does not exist", func() {
+ setupHhgAllowanceParameter()
+
+ entitlement := models.Entitlement{
+ ID: uuid.Must(uuid.NewV4()),
+ }
+
+ restrictor := NewWeightRestrictor()
+ updatedEntitlement, err := restrictor.RemoveWeightRestrictionFromEntitlement(suite.AppContextForTest(), entitlement, etag.GenerateEtag(entitlement.UpdatedAt))
+ suite.Error(err)
+ suite.Nil(updatedEntitlement)
+ suite.IsType(apperror.NotFoundError{}, err)
+ })
+}
diff --git a/pkg/services/move/move_weights.go b/pkg/services/move/move_weights.go
index e1fbda2e4f1..0c88fddefba 100644
--- a/pkg/services/move/move_weights.go
+++ b/pkg/services/move/move_weights.go
@@ -23,12 +23,13 @@ const RiskOfExcessThreshold = .9
const AutoReweighRequestThreshold = .9
type moveWeights struct {
- ReweighRequestor services.ShipmentReweighRequester
+ ReweighRequestor services.ShipmentReweighRequester
+ WeightAllotmentFetcher services.WeightAllotmentFetcher
}
// NewMoveWeights creates a new moveWeights service
-func NewMoveWeights(reweighRequestor services.ShipmentReweighRequester) services.MoveWeights {
- return &moveWeights{ReweighRequestor: reweighRequestor}
+func NewMoveWeights(reweighRequestor services.ShipmentReweighRequester, weightAllotmentFetcher services.WeightAllotmentFetcher) services.MoveWeights {
+ return &moveWeights{ReweighRequestor: reweighRequestor, WeightAllotmentFetcher: weightAllotmentFetcher}
}
func validateAndSave(appCtx appcontext.AppContext, move *models.Move) (*validate.Errors, error) {
@@ -98,7 +99,10 @@ func (w moveWeights) CheckExcessWeight(appCtx appcontext.AppContext, moveID uuid
return nil, nil, errors.New("could not determine excess weight entitlement without dependents authorization value")
}
- totalWeightAllowance := models.GetWeightAllotment(*move.Orders.Grade, move.Orders.OrdersType)
+ totalWeightAllowance, err := w.WeightAllotmentFetcher.GetWeightAllotment(appCtx, string(*move.Orders.Grade), move.Orders.OrdersType)
+ if err != nil {
+ return nil, nil, err
+ }
overallWeightAllowance := totalWeightAllowance.TotalWeightSelf
if *move.Orders.Entitlement.DependentsAuthorized {
@@ -261,7 +265,10 @@ func (w moveWeights) CheckAutoReweigh(appCtx appcontext.AppContext, moveID uuid.
return nil, errors.New("could not determine excess weight entitlement without dependents authorization value")
}
- totalWeightAllowance := models.GetWeightAllotment(*move.Orders.Grade, move.Orders.OrdersType)
+ totalWeightAllowance, err := w.WeightAllotmentFetcher.GetWeightAllotment(appCtx, string(*move.Orders.Grade), move.Orders.OrdersType)
+ if err != nil {
+ return nil, err
+ }
overallWeightAllowance := totalWeightAllowance.TotalWeightSelf
if *move.Orders.Entitlement.DependentsAuthorized {
diff --git a/pkg/services/move/move_weights_test.go b/pkg/services/move/move_weights_test.go
index 6528830e2e4..60d716c1241 100644
--- a/pkg/services/move/move_weights_test.go
+++ b/pkg/services/move/move_weights_test.go
@@ -8,6 +8,7 @@ import (
"github.com/transcom/mymove/pkg/auth"
"github.com/transcom/mymove/pkg/factory"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/mocks"
mtoshipment "github.com/transcom/mymove/pkg/services/mto_shipment"
"github.com/transcom/mymove/pkg/testdatagen"
@@ -15,7 +16,9 @@ import (
)
func (suite *MoveServiceSuite) TestExcessWeight() {
- moveWeights := NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ waf := entitlements.NewWeightAllotmentFetcher()
+
+ moveWeights := NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
suite.Run("qualifies move for excess weight when an approved shipment estimated weight is updated within threshold", func() {
// The default weight allotment for this move is 8000 and the threshold is 90% of that
@@ -484,9 +487,10 @@ func (suite *MoveServiceSuite) TestExcessWeight() {
}
func (suite *MoveServiceSuite) TestAutoReweigh() {
- moveWeights := NewMoveWeights(mtoshipment.NewShipmentReweighRequester())
+ waf := entitlements.NewWeightAllotmentFetcher()
+ moveWeights := NewMoveWeights(mtoshipment.NewShipmentReweighRequester(), waf)
- suite.Run("requests reweigh on shipment if the acutal weight is 90% of the weight allowance", func() {
+ suite.Run("requests reweigh on shipment if the actual weight is 90% of the weight allowance", func() {
// The default weight allotment for this move is 8000 and the threshold is 90% of that
approvedMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
now := time.Now()
@@ -524,7 +528,7 @@ func (suite *MoveServiceSuite) TestAutoReweigh() {
suite.Run("does not request reweigh on shipments when below 90% of weight allowance threshold", func() {
mockedReweighRequestor := mocks.ShipmentReweighRequester{}
- mockedWeightService := NewMoveWeights(&mockedReweighRequestor)
+ mockedWeightService := NewMoveWeights(&mockedReweighRequestor, waf)
approvedMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
@@ -615,7 +619,7 @@ func (suite *MoveServiceSuite) TestAutoReweigh() {
suite.Run("does not request reweigh when shipments aren't in approved statuses", func() {
mockedReweighRequestor := mocks.ShipmentReweighRequester{}
- mockedWeightService := NewMoveWeights(&mockedReweighRequestor)
+ mockedWeightService := NewMoveWeights(&mockedReweighRequestor, waf)
approvedMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
now := time.Now()
@@ -664,7 +668,7 @@ func (suite *MoveServiceSuite) TestAutoReweigh() {
suite.Run("uses lower reweigh weight on shipments that already have reweighs", func() {
mockedReweighRequestor := mocks.ShipmentReweighRequester{}
- mockedWeightService := NewMoveWeights(&mockedReweighRequestor)
+ mockedWeightService := NewMoveWeights(&mockedReweighRequestor, waf)
approvedMove := factory.BuildAvailableToPrimeMove(suite.DB(), nil, nil)
now := time.Now()
diff --git a/pkg/services/move_task_order/move_task_order_fetcher.go b/pkg/services/move_task_order/move_task_order_fetcher.go
index 1d30aef5ceb..b42d76729d2 100644
--- a/pkg/services/move_task_order/move_task_order_fetcher.go
+++ b/pkg/services/move_task_order/move_task_order_fetcher.go
@@ -20,11 +20,14 @@ import (
)
type moveTaskOrderFetcher struct {
+ waf services.WeightAllotmentFetcher
}
// NewMoveTaskOrderFetcher creates a new struct with the service dependencies
-func NewMoveTaskOrderFetcher() services.MoveTaskOrderFetcher {
- return &moveTaskOrderFetcher{}
+func NewMoveTaskOrderFetcher(weightAllotmentFetcher services.WeightAllotmentFetcher) services.MoveTaskOrderFetcher {
+ return &moveTaskOrderFetcher{
+ waf: weightAllotmentFetcher,
+ }
}
// ListAllMoveTaskOrders retrieves all Move Task Orders that may or may not be available to prime, and may or may not be enabled.
@@ -196,6 +199,16 @@ func (f moveTaskOrderFetcher) FetchMoveTaskOrder(appCtx appcontext.AppContext, s
}
}
+ // Now that we have the move and order, construct the allotment (hhg allowance)
+ // Only fetch if grade is not nil
+ if mto.Orders.Grade != nil {
+ allotment, err := f.waf.GetWeightAllotment(appCtx, string(*mto.Orders.Grade), mto.Orders.OrdersType)
+ if err != nil {
+ return nil, err
+ }
+ mto.Orders.Entitlement.WeightAllotted = &allotment
+ }
+
// Due to a bug in Pop for EagerPreload the New Address of the DeliveryAddressUpdate and the PortLocation (City, Country, UsPostRegionCity.UsPostRegion.State") must be loaded manually.
// The bug occurs in EagerPreload when there are two or more eager paths with 3+ levels
// where the first 2 levels match. For example:
diff --git a/pkg/services/move_task_order/move_task_order_fetcher_test.go b/pkg/services/move_task_order/move_task_order_fetcher_test.go
index a80be4aa524..6000b23d49a 100644
--- a/pkg/services/move_task_order/move_task_order_fetcher_test.go
+++ b/pkg/services/move_task_order/move_task_order_fetcher_test.go
@@ -11,12 +11,14 @@ import (
"github.com/transcom/mymove/pkg/factory"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
m "github.com/transcom/mymove/pkg/services/move_task_order"
"github.com/transcom/mymove/pkg/testdatagen"
"github.com/transcom/mymove/pkg/uploader"
)
func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderFetcher() {
+ waf := entitlements.NewWeightAllotmentFetcher()
setupTestData := func() (models.Move, models.MTOShipment) {
@@ -61,7 +63,7 @@ func (suite *MoveTaskOrderServiceSuite) TestMoveTaskOrderFetcher() {
return expectedMTO, primeShipment
}
- mtoFetcher := m.NewMoveTaskOrderFetcher()
+ mtoFetcher := m.NewMoveTaskOrderFetcher(waf)
suite.Run("Success with fetching a MTO that has a shipment address update", func() {
traits := []factory.Trait{factory.GetTraitShipmentAddressUpdateApproved}
@@ -576,8 +578,9 @@ func (suite *MoveTaskOrderServiceSuite) TestGetMoveTaskOrderFetcher() {
return expectedMTO
}
+ waf := entitlements.NewWeightAllotmentFetcher()
- mtoFetcher := m.NewMoveTaskOrderFetcher()
+ mtoFetcher := m.NewMoveTaskOrderFetcher(waf)
suite.Run("success getting a move using GetMove for Prime user", func() {
expectedMTO := setupTestData()
@@ -705,6 +708,8 @@ func (suite *MoveTaskOrderServiceSuite) TestListAllMoveTaskOrdersFetcher() {
// Set up a hidden move so we can check if it's in the output:
now := time.Now()
show := false
+ waf := entitlements.NewWeightAllotmentFetcher()
+
setupTestData := func() (models.Move, models.Move, models.MTOShipment) {
hiddenMTO := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{
{
@@ -743,7 +748,7 @@ func (suite *MoveTaskOrderServiceSuite) TestListAllMoveTaskOrdersFetcher() {
return hiddenMTO, mto, primeShipment
}
- mtoFetcher := m.NewMoveTaskOrderFetcher()
+ mtoFetcher := m.NewMoveTaskOrderFetcher(waf)
suite.Run("all move task orders", func() {
hiddenMTO, mto, _ := setupTestData()
@@ -850,6 +855,7 @@ func (suite *MoveTaskOrderServiceSuite) TestListAllMoveTaskOrdersFetcher() {
func (suite *MoveTaskOrderServiceSuite) TestListPrimeMoveTaskOrdersFetcher() {
now := time.Now()
+ waf := entitlements.NewWeightAllotmentFetcher()
// Set up a hidden move so we can check if it's in the output:
hiddenMove := factory.BuildAvailableToPrimeMove(suite.DB(), []factory.Customization{
{
@@ -879,7 +885,7 @@ func (suite *MoveTaskOrderServiceSuite) TestListPrimeMoveTaskOrdersFetcher() {
suite.Require().NoError(suite.DB().RawQuery("UPDATE mto_shipments SET updated_at=$1 WHERE id=$2;",
now.Add(-10*time.Second), shipmentForPrimeMove4.ID).Exec())
- fetcher := m.NewMoveTaskOrderFetcher()
+ fetcher := m.NewMoveTaskOrderFetcher(waf)
page := int64(1)
perPage := int64(20)
// filling out search params to allow for pagination
@@ -912,6 +918,8 @@ func (suite *MoveTaskOrderServiceSuite) TestListPrimeMoveTaskOrdersFetcher() {
}
func (suite *MoveTaskOrderServiceSuite) TestListPrimeMoveTaskOrdersAmendmentsFetcher() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
suite.Run("Test with and without filter of moves containing amendments", func() {
now := time.Now()
// Set up a hidden move so we can check if it's in the output:
@@ -995,7 +1003,7 @@ func (suite *MoveTaskOrderServiceSuite) TestListPrimeMoveTaskOrdersAmendmentsFet
suite.Require().NoError(suite.DB().RawQuery("UPDATE mto_shipments SET updated_at=$1 WHERE id=$2;",
now.Add(-10*time.Second), shipmentForPrimeMove4.ID).Exec())
- fetcher := m.NewMoveTaskOrderFetcher()
+ fetcher := m.NewMoveTaskOrderFetcher(waf)
page := int64(1)
perPage := int64(20)
// filling out search params to allow for pagination
@@ -1071,7 +1079,7 @@ func (suite *MoveTaskOrderServiceSuite) TestListPrimeMoveTaskOrdersAmendmentsFet
suite.Require().NoError(suite.DB().RawQuery("UPDATE moves SET updated_at=$1 WHERE id IN ($2, $3);",
now.Add(-10*time.Second), primeMove1.ID, primeMove2.ID).Exec())
- fetcher := m.NewMoveTaskOrderFetcher()
+ fetcher := m.NewMoveTaskOrderFetcher(waf)
page := int64(1)
perPage := int64(20)
// filling out search params to allow for pagination
diff --git a/pkg/services/move_task_order/move_task_order_updater.go b/pkg/services/move_task_order/move_task_order_updater.go
index 25fbec6856a..d0cd55aed37 100644
--- a/pkg/services/move_task_order/move_task_order_updater.go
+++ b/pkg/services/move_task_order/move_task_order_updater.go
@@ -15,6 +15,7 @@ import (
"github.com/transcom/mymove/pkg/etag"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/order"
"github.com/transcom/mymove/pkg/services/query"
)
@@ -31,7 +32,12 @@ type moveTaskOrderUpdater struct {
// NewMoveTaskOrderUpdater creates a new struct with the service dependencies
func NewMoveTaskOrderUpdater(builder UpdateMoveTaskOrderQueryBuilder, serviceItemCreator services.MTOServiceItemCreator, moveRouter services.MoveRouter, signedCertificationCreator services.SignedCertificationCreator, signedCertificationUpdater services.SignedCertificationUpdater, estimator services.PPMEstimator) services.MoveTaskOrderUpdater {
- return &moveTaskOrderUpdater{moveTaskOrderFetcher{}, builder, serviceItemCreator, moveRouter, signedCertificationCreator, signedCertificationUpdater, estimator}
+ // Fetcher dependency
+ waf := entitlements.NewWeightAllotmentFetcher()
+
+ return &moveTaskOrderUpdater{moveTaskOrderFetcher{
+ waf: waf,
+ }, builder, serviceItemCreator, moveRouter, signedCertificationCreator, signedCertificationUpdater, estimator}
}
// UpdateStatusServiceCounselingCompleted updates the status on the move (move task order) to service counseling completed
diff --git a/pkg/services/mto_shipment/mto_shipment_updater_test.go b/pkg/services/mto_shipment/mto_shipment_updater_test.go
index bfced125206..c7075402d1f 100644
--- a/pkg/services/mto_shipment/mto_shipment_updater_test.go
+++ b/pkg/services/mto_shipment/mto_shipment_updater_test.go
@@ -19,6 +19,7 @@ import (
notificationMocks "github.com/transcom/mymove/pkg/notifications/mocks"
"github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services/address"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/fetch"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
mockservices "github.com/transcom/mymove/pkg/services/mocks"
@@ -54,7 +55,8 @@ func (suite *MTOShipmentServiceSuite) TestMTOShipmentUpdater() {
false,
).Return(1000, nil)
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester())
+ waf := entitlements.NewWeightAllotmentFetcher()
+ moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester(), waf)
mockShipmentRecalculator := mockservices.PaymentRequestShipmentRecalculator{}
mockShipmentRecalculator.On("ShipmentRecalculatePaymentRequest",
mock.AnythingOfType("*appcontext.appContext"),
@@ -2775,6 +2777,8 @@ func (suite *MTOShipmentServiceSuite) TestUpdateMTOShipmentStatus() {
func (suite *MTOShipmentServiceSuite) TestMTOShipmentsMTOAvailableToPrime() {
now := time.Now()
+ waf := entitlements.NewWeightAllotmentFetcher()
+
hide := false
var primeShipment models.MTOShipment
var nonPrimeShipment models.MTOShipment
@@ -2805,7 +2809,7 @@ func (suite *MTOShipmentServiceSuite) TestMTOShipmentsMTOAvailableToPrime() {
fetcher := fetch.NewFetcher(builder)
planner := &mocks.Planner{}
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester(), waf)
mockShipmentRecalculator := mockservices.PaymentRequestShipmentRecalculator{}
mockShipmentRecalculator.On("ShipmentRecalculatePaymentRequest",
mock.AnythingOfType("*appcontext.appContext"),
@@ -2873,8 +2877,10 @@ func (suite *MTOShipmentServiceSuite) TestUpdateShipmentEstimatedWeightMoveExces
builder := query.NewQueryBuilder()
fetcher := fetch.NewFetcher(builder)
planner := &mocks.Planner{}
+ waf := entitlements.NewWeightAllotmentFetcher()
+
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester(), waf)
mockShipmentRecalculator := mockservices.PaymentRequestShipmentRecalculator{}
mockShipmentRecalculator.On("ShipmentRecalculatePaymentRequest",
mock.AnythingOfType("*appcontext.appContext"),
@@ -3054,10 +3060,12 @@ func (suite *MTOShipmentServiceSuite) TestUpdateShipmentEstimatedWeightMoveExces
func (suite *MTOShipmentServiceSuite) TestUpdateShipmentActualWeightAutoReweigh() {
builder := query.NewQueryBuilder()
+ waf := entitlements.NewWeightAllotmentFetcher()
+
fetcher := fetch.NewFetcher(builder)
planner := &mocks.Planner{}
moveRouter := moveservices.NewMoveRouter()
- moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester())
+ moveWeights := moveservices.NewMoveWeights(NewShipmentReweighRequester(), waf)
mockShipmentRecalculator := mockservices.PaymentRequestShipmentRecalculator{}
mockShipmentRecalculator.On("ShipmentRecalculatePaymentRequest",
mock.AnythingOfType("*appcontext.appContext"),
diff --git a/pkg/services/mto_shipment/shipment_approver_test.go b/pkg/services/mto_shipment/shipment_approver_test.go
index e0a80dfdf87..265b9133cd1 100644
--- a/pkg/services/mto_shipment/shipment_approver_test.go
+++ b/pkg/services/mto_shipment/shipment_approver_test.go
@@ -17,6 +17,7 @@ import (
"github.com/transcom/mymove/pkg/route"
"github.com/transcom/mymove/pkg/route/mocks"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/ghcrateengine"
shipmentmocks "github.com/transcom/mymove/pkg/services/mocks"
moverouter "github.com/transcom/mymove/pkg/services/move"
@@ -85,6 +86,7 @@ func (suite *MTOShipmentServiceSuite) createApproveShipmentSubtestData() (subtes
router := NewShipmentRouter()
builder := query.NewQueryBuilder()
+ waf := entitlements.NewWeightAllotmentFetcher()
moveRouter := moverouter.NewMoveRouter()
planner := &mocks.Planner{}
planner.On("ZipTransitDistance",
@@ -96,7 +98,7 @@ func (suite *MTOShipmentServiceSuite) createApproveShipmentSubtestData() (subtes
).Return(400, nil)
siCreator := mtoserviceitem.NewMTOServiceItemCreator(planner, builder, moveRouter, ghcrateengine.NewDomesticUnpackPricer(), ghcrateengine.NewDomesticPackPricer(), ghcrateengine.NewDomesticLinehaulPricer(), ghcrateengine.NewDomesticShorthaulPricer(), ghcrateengine.NewDomesticOriginPricer(), ghcrateengine.NewDomesticDestinationPricer(), ghcrateengine.NewFuelSurchargePricer())
subtestData.planner = &mocks.Planner{}
- subtestData.moveWeights = moverouter.NewMoveWeights(NewShipmentReweighRequester())
+ subtestData.moveWeights = moverouter.NewMoveWeights(NewShipmentReweighRequester(), waf)
subtestData.shipmentApprover = NewShipmentApprover(router, siCreator, subtestData.planner, subtestData.moveWeights)
subtestData.mockedShipmentApprover = NewShipmentApprover(subtestData.mockedShipmentRouter, siCreator, subtestData.planner, subtestData.moveWeights)
@@ -258,7 +260,8 @@ func (suite *MTOShipmentServiceSuite) TestApproveShipment() {
})
shipmentRouter := NewShipmentRouter()
- moveWeights := moverouter.NewMoveWeights(NewShipmentReweighRequester())
+ waf := entitlements.NewWeightAllotmentFetcher()
+ moveWeights := moverouter.NewMoveWeights(NewShipmentReweighRequester(), waf)
var serviceItemCreator services.MTOServiceItemCreator
appCtx := suite.AppContextWithSessionForTest(&auth.Session{
ApplicationName: auth.OfficeApp,
diff --git a/pkg/services/order/order_fetcher.go b/pkg/services/order/order_fetcher.go
index 524271a345b..6b6c57840c4 100644
--- a/pkg/services/order/order_fetcher.go
+++ b/pkg/services/order/order_fetcher.go
@@ -25,6 +25,7 @@ import (
const RFC3339Micro = "2006-01-02T15:04:05.999999Z07:00"
type orderFetcher struct {
+ waf services.WeightAllotmentFetcher
}
// QueryOption defines the type for the functional arguments used for private functions in OrderFetcher
@@ -610,8 +611,8 @@ func (f orderFetcher) ListAllOrderLocations(appCtx appcontext.AppContext, office
}
// NewOrderFetcher creates a new struct with the service dependencies
-func NewOrderFetcher() services.OrderFetcher {
- return &orderFetcher{}
+func NewOrderFetcher(weightAllotmentFetcher services.WeightAllotmentFetcher) services.OrderFetcher {
+ return &orderFetcher{waf: weightAllotmentFetcher}
}
// FetchOrder retrieves an Order for a given UUID
@@ -635,6 +636,15 @@ func (f orderFetcher) FetchOrder(appCtx appcontext.AppContext, orderID uuid.UUID
}
}
+ // Construct weight allotted if grade is present
+ if order.Grade != nil {
+ allotment, err := f.waf.GetWeightAllotment(appCtx, string(*order.Grade), order.OrdersType)
+ if err != nil {
+ return nil, err
+ }
+ order.Entitlement.WeightAllotted = &allotment
+ }
+
// Due to a bug in pop (https://github.com/gobuffalo/pop/issues/578), we
// cannot eager load the address as "OriginDutyLocation.Address" because
// OriginDutyLocation is a pointer.
diff --git a/pkg/services/order/order_fetcher_test.go b/pkg/services/order/order_fetcher_test.go
index 0f9332c1d9e..15aa5d9863a 100644
--- a/pkg/services/order/order_fetcher_test.go
+++ b/pkg/services/order/order_fetcher_test.go
@@ -12,6 +12,7 @@ import (
"github.com/transcom/mymove/pkg/models"
"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"
@@ -21,7 +22,8 @@ import (
func (suite *OrderServiceSuite) TestFetchOrder() {
expectedMove := factory.BuildMove(suite.DB(), nil, nil)
expectedOrder := expectedMove.Orders
- orderFetcher := NewOrderFetcher()
+ waf := entitlements.NewWeightAllotmentFetcher()
+ orderFetcher := NewOrderFetcher(waf)
order, err := orderFetcher.FetchOrder(suite.AppContextForTest(), expectedOrder.ID)
suite.FatalNoError(err)
@@ -51,7 +53,7 @@ func (suite *OrderServiceSuite) TestFetchOrderWithEmptyFields() {
// noticed an exception due to trying to load empty OriginDutyLocations.
// This was not caught by any tests, so we're adding one now.
expectedOrder := factory.BuildOrder(suite.DB(), nil, nil)
-
+ waf := entitlements.NewWeightAllotmentFetcher()
expectedOrder.Entitlement = nil
expectedOrder.EntitlementID = nil
expectedOrder.Grade = nil
@@ -66,7 +68,7 @@ func (suite *OrderServiceSuite) TestFetchOrderWithEmptyFields() {
},
}, nil)
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
order, err := orderFetcher.FetchOrder(suite.AppContextForTest(), expectedOrder.ID)
suite.FatalNoError(err)
@@ -76,7 +78,7 @@ func (suite *OrderServiceSuite) TestFetchOrderWithEmptyFields() {
}
func (suite *OrderServiceSuite) TestListOrders() {
-
+ waf := entitlements.NewWeightAllotmentFetcher()
agfmPostalCode := "06001"
setupTestData := func() (models.OfficeUser, models.Move, auth.Session) {
@@ -97,7 +99,7 @@ func (suite *OrderServiceSuite) TestListOrders() {
factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), agfmPostalCode, "AGFM")
return officeUser, move, session
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("returns moves", func() {
// Under test: ListOrders
@@ -729,6 +731,8 @@ func (suite *OrderServiceSuite) TestListOrders() {
}
func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
setupTestData := func(officeUserGBLOC string) (models.OfficeUser, auth.Session) {
officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), []factory.Customization{
@@ -758,7 +762,7 @@ func (suite *OrderServiceSuite) TestListDestinationRequestsOrders() {
return officeUser, session
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("returns moves for KKFA GBLOC when destination address is in KKFA GBLOC", func() {
officeUser, session := setupTestData("KKFA")
@@ -1347,7 +1351,8 @@ func (suite *OrderServiceSuite) TestListOrderWithAssignedUserSingle() {
suite.Equal(createdMove.SCAssignedUser.LastName, moves[0].SCAssignedUser.LastName)
}
func (suite *OrderServiceSuite) TestListOrdersUSMCGBLOC() {
- orderFetcher := NewOrderFetcher()
+ waf := entitlements.NewWeightAllotmentFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("returns USMC order for USMC office user", func() {
marines := models.AffiliationMARINES
@@ -1483,7 +1488,8 @@ func buildPPMShipmentCloseoutComplete(suite *OrderServiceSuite, move models.Move
return ppm
}
func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForArmyAirforce() {
- orderFetcher := NewOrderFetcher()
+ waf := entitlements.NewWeightAllotmentFetcher()
+ orderFetcher := NewOrderFetcher(waf)
var session auth.Session
@@ -1544,7 +1550,8 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForArmyAirforce() {
}
func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMarines() {
- orderFetcher := NewOrderFetcher()
+ waf := entitlements.NewWeightAllotmentFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("returns Navy order for NAVY office user when there's a ppm shipment in closeout", func() {
// It doesn't matter what the Origin GBLOC is for the move. Only the navy
@@ -1707,8 +1714,10 @@ func (suite *OrderServiceSuite) TestListOrdersPPMCloseoutForNavyCoastGuardAndMar
}
func (suite *OrderServiceSuite) TestListOrdersMarines() {
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("does not return moves where the service member affiliation is Marines for non-USMC office user", func() {
- orderFetcher := NewOrderFetcher()
+
+ orderFetcher := NewOrderFetcher(waf)
marines := models.AffiliationMARINES
factory.BuildMoveWithShipment(suite.DB(), []factory.Customization{
{
@@ -1736,7 +1745,7 @@ func (suite *OrderServiceSuite) TestListOrdersMarines() {
func (suite *OrderServiceSuite) TestListOrdersWithEmptyFields() {
expectedOrder := factory.BuildOrder(suite.DB(), nil, nil)
-
+ waf := entitlements.NewWeightAllotmentFetcher()
expectedOrder.Entitlement = nil
expectedOrder.EntitlementID = nil
expectedOrder.Grade = nil
@@ -1786,7 +1795,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithEmptyFields() {
AccessToken: "fakeAccessToken",
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
moves, _, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{PerPage: models.Int64Pointer(1), Page: models.Int64Pointer(1)})
suite.FatalNoError(err)
@@ -1796,6 +1805,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithEmptyFields() {
func (suite *OrderServiceSuite) TestListOrdersWithPagination() {
officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
+ waf := entitlements.NewWeightAllotmentFetcher()
session := auth.Session{
ApplicationName: auth.OfficeApp,
Roles: officeUser.User.Roles,
@@ -1808,7 +1818,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithPagination() {
factory.BuildMoveWithShipment(suite.DB(), nil, nil)
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
params := services.ListOrderParams{Page: models.Int64Pointer(1), PerPage: models.Int64Pointer(1)}
moves, count, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, ¶ms)
@@ -1827,7 +1837,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithSortOrder() {
affiliation := models.AffiliationNAVY
edipi := "9999999999"
var officeUser models.OfficeUser
-
+ waf := entitlements.NewWeightAllotmentFetcher()
// SET UP: Dates for sorting by Requested Move Date
// - We want dates 2 and 3 to sandwich requestedMoveDate1 so we can test that the min() query is working
requestedMoveDate1 := time.Date(testdatagen.GHCTestYear, 02, 20, 0, 0, 0, 0, time.UTC)
@@ -1889,7 +1899,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithSortOrder() {
return expectedMove1, expectedMove2, session
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("Sort by locator code", func() {
expectedMove1, expectedMove2, session := setupTestData()
@@ -2052,6 +2062,7 @@ func getPPMShipmentWithCloseoutOfficeNeedsCloseout(suite *OrderServiceSuite, clo
func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCloseoutColumnsSort() {
defaultShipmentPickupPostalCode := "90210"
+ waf := entitlements.NewWeightAllotmentFetcher()
setupTestData := func() models.OfficeUser {
// Make an office user → GBLOC X
officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
@@ -2064,7 +2075,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl
return officeUser
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
var session auth.Session
@@ -2328,7 +2339,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithPPMCl
}
func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithGBLOCSortFilter() {
-
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("Filter by origin GBLOC", func() {
// TESTCASE SCENARIO
@@ -2398,7 +2409,7 @@ func (suite *OrderServiceSuite) TestListOrdersNeedingServicesCounselingWithGBLOC
},
}, nil)
// Setup and run the function under test requesting status NEEDS SERVICE COUNSELING
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
statuses := []string{"NEEDS SERVICE COUNSELING"}
// Sort by origin GBLOC, filter by status
params := services.ListOrderParams{Sort: models.StringPointer("originGBLOC"), Order: models.StringPointer("asc"), Status: statuses}
@@ -2420,6 +2431,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithNTSRelease() {
},
},
}, nil)
+ waf := entitlements.NewWeightAllotmentFetcher()
// Make a TOO user and the postal code to GBLOC link.
tooOfficeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
session := auth.Session{
@@ -2430,7 +2442,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithNTSRelease() {
AccessToken: "fakeAccessToken",
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), tooOfficeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{})
suite.FatalNoError(err)
@@ -2441,7 +2453,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithNTSRelease() {
func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPM() {
postalCode := "50309"
partialPPMType := models.MovePPMTypePARTIAL
-
+ waf := entitlements.NewWeightAllotmentFetcher()
ppmShipment := factory.BuildPPMShipment(suite.DB(), []factory.Customization{
{
Model: models.Order{
@@ -2474,7 +2486,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPM() {
// GBLOC for the below doesn't really matter, it just means the query for the moves passes the inner join in ListOrders
factory.FetchOrBuildPostalCodeToGBLOC(suite.DB(), ppmShipment.PickupAddress.PostalCode, tooOfficeUser.TransportationOffice.Gbloc)
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), tooOfficeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{})
suite.FatalNoError(err)
suite.Equal(1, moveCount)
@@ -2484,7 +2496,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPM() {
func (suite *OrderServiceSuite) TestListOrdersWithViewAsGBLOCParam() {
var hqOfficeUser models.OfficeUser
var hqOfficeUserAGFM models.OfficeUser
-
+ waf := entitlements.NewWeightAllotmentFetcher()
requestedMoveDate1 := time.Date(testdatagen.GHCTestYear, 02, 20, 0, 0, 0, 0, time.UTC)
requestedMoveDate2 := time.Date(testdatagen.GHCTestYear, 03, 03, 0, 0, 0, 0, time.UTC)
@@ -2566,7 +2578,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithViewAsGBLOCParam() {
return expectedMove1, expectedMove2, expectedShipment3, hqSession, hqSessionAGFM
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("Sort by locator code", func() {
expectedMove1, expectedMove2, expectedShipment3, hqSession, hqSessionAGFM := setupTestData()
@@ -2606,6 +2618,7 @@ func (suite *OrderServiceSuite) TestListOrdersWithViewAsGBLOCParam() {
func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPMWithDeletedShipment() {
postalCode := "50309"
deletedAt := time.Now()
+ waf := entitlements.NewWeightAllotmentFetcher()
move := factory.BuildMove(suite.DB(), []factory.Customization{
{
Model: models.Move{
@@ -2648,7 +2661,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPMWithDeletedShipment()
AccessToken: "fakeAccessToken",
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), tooOfficeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{Status: []string{string(models.MoveStatusSUBMITTED)}})
suite.FatalNoError(err)
suite.Equal(0, moveCount)
@@ -2658,6 +2671,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPMWithDeletedShipment()
func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPMWithOneDeletedShipmentButOtherExists() {
postalCode := "50309"
deletedAt := time.Now()
+ waf := entitlements.NewWeightAllotmentFetcher()
move := factory.BuildMove(suite.DB(), []factory.Customization{
{
Model: models.Move{
@@ -2728,7 +2742,7 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPMWithOneDeletedShipmen
AccessToken: "fakeAccessToken",
}
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
moves, moveCount, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), tooOfficeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{})
suite.FatalNoError(err)
suite.Equal(1, moveCount)
@@ -2736,8 +2750,9 @@ func (suite *OrderServiceSuite) TestListOrdersForTOOWithPPMWithOneDeletedShipmen
}
func (suite *OrderServiceSuite) TestListAllOrderLocations() {
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("returns a list of all order locations in the current users queue", func() {
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeServicesCounselor})
session := auth.Session{
ApplicationName: auth.OfficeApp,
@@ -2756,8 +2771,9 @@ func (suite *OrderServiceSuite) TestListAllOrderLocations() {
}
func (suite *OrderServiceSuite) TestListAllOrderLocationsWithViewAsGBLOCParam() {
+ waf := entitlements.NewWeightAllotmentFetcher()
suite.Run("returns a list of all order locations in the current users queue", func() {
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
officeUserFetcher := officeuserservice.NewOfficeUserFetcherPop()
movesContainOriginDutyLocation := func(moves models.Moves, keyword string) func() (success bool) {
return func() (success bool) {
@@ -2855,26 +2871,26 @@ func (suite *OrderServiceSuite) TestListAllOrderLocationsWithViewAsGBLOCParam()
func (suite *OrderServiceSuite) TestOriginDutyLocationFilter() {
var session auth.Session
+ waf := entitlements.NewWeightAllotmentFetcher()
var expectedMove models.Move
var officeUser models.OfficeUser
- orderFetcher := NewOrderFetcher()
- suite.PreloadData(func() {
- setupTestData := func() (models.OfficeUser, models.Move, auth.Session) {
- officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
- session := auth.Session{
- ApplicationName: auth.OfficeApp,
- Roles: officeUser.User.Roles,
- OfficeUserID: officeUser.ID,
- IDToken: "fake_token",
- AccessToken: "fakeAccessToken",
- }
- move := factory.BuildMoveWithShipment(suite.DB(), nil, nil)
- return officeUser, move, session
+ orderFetcher := NewOrderFetcher(waf)
+ setupTestData := func() (models.OfficeUser, models.Move, auth.Session) {
+ officeUser := factory.BuildOfficeUserWithRoles(suite.DB(), nil, []roles.RoleType{roles.RoleTypeTOO})
+ session := auth.Session{
+ ApplicationName: auth.OfficeApp,
+ Roles: officeUser.User.Roles,
+ OfficeUserID: officeUser.ID,
+ IDToken: "fake_token",
+ AccessToken: "fakeAccessToken",
}
- officeUser, expectedMove, session = setupTestData()
- })
- locationName := expectedMove.Orders.OriginDutyLocation.Name
+ move := factory.BuildMoveWithShipment(suite.DB(), nil, nil)
+ return officeUser, move, session
+ }
+
suite.Run("Returns orders matching full originDutyLocation name filter", func() {
+ officeUser, expectedMove, session = setupTestData()
+ locationName := expectedMove.Orders.OriginDutyLocation.Name
expectedMoves, _, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{OriginDutyLocation: strings.Split(locationName, " ")})
suite.NoError(err)
suite.Equal(1, len(expectedMoves))
@@ -2882,6 +2898,8 @@ func (suite *OrderServiceSuite) TestOriginDutyLocationFilter() {
})
suite.Run("Returns orders matching partial originDutyLocation name filter", func() {
+ officeUser, expectedMove, session = setupTestData()
+ locationName := expectedMove.Orders.OriginDutyLocation.Name
//Split the location name and retrieve a substring (first string) for the search param
partialParamSearch := strings.Split(locationName, " ")[0]
expectedMoves, _, err := orderFetcher.ListOrders(suite.AppContextWithSessionForTest(&session), officeUser.ID, roles.RoleTypeTOO, &services.ListOrderParams{OriginDutyLocation: strings.Split(partialParamSearch, " ")})
@@ -2892,6 +2910,8 @@ func (suite *OrderServiceSuite) TestOriginDutyLocationFilter() {
}
func (suite *OrderServiceSuite) TestListOrdersFilteredByCustomerName() {
+ waf := entitlements.NewWeightAllotmentFetcher()
+
serviceMemberFirstName := "Margaret"
serviceMemberLastName := "Starlight"
edipi := "9999999998"
@@ -2950,7 +2970,7 @@ func (suite *OrderServiceSuite) TestListOrdersFilteredByCustomerName() {
}
})
- orderFetcher := NewOrderFetcher()
+ orderFetcher := NewOrderFetcher(waf)
suite.Run("list moves by customer name - full name (last, first)", func() {
// Search "Spacemen, Margaret"
diff --git a/pkg/services/order/order_updater.go b/pkg/services/order/order_updater.go
index 02b8c848ca5..12821783d7a 100644
--- a/pkg/services/order/order_updater.go
+++ b/pkg/services/order/order_updater.go
@@ -17,6 +17,7 @@ import (
"github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/query"
"github.com/transcom/mymove/pkg/storage"
"github.com/transcom/mymove/pkg/uploader"
@@ -48,7 +49,10 @@ func (f *orderUpdater) UpdateOrderAsTOO(appCtx appcontext.AppContext, orderID uu
return &models.Order{}, uuid.Nil, apperror.NewInvalidInputError(orderID, nil, nil, "SAC cannot be more than 80 characters")
}
- orderToUpdate := orderFromTOOPayload(appCtx, *order, payload)
+ orderToUpdate, err := orderFromTOOPayload(appCtx, *order, payload)
+ if err != nil {
+ return nil, uuid.Nil, err
+ }
return f.updateOrderAsTOO(appCtx, orderToUpdate, CheckRequiredFields())
}
@@ -70,7 +74,10 @@ func (f *orderUpdater) UpdateOrderAsCounselor(appCtx appcontext.AppContext, orde
return &models.Order{}, uuid.Nil, apperror.NewInvalidInputError(orderID, nil, nil, "SAC cannot be more than 80 characters")
}
- orderToUpdate := orderFromCounselingPayload(*order, payload)
+ orderToUpdate, err := orderFromCounselingPayload(appCtx, *order, payload)
+ if err != nil {
+ return &models.Order{}, uuid.Nil, nil
+ }
return f.updateOrder(appCtx, orderToUpdate, CheckRequiredFields())
}
@@ -87,7 +94,10 @@ func (f *orderUpdater) UpdateAllowanceAsTOO(appCtx appcontext.AppContext, orderI
return &models.Order{}, uuid.Nil, apperror.NewPreconditionFailedError(orderID, query.StaleIdentifierError{StaleIdentifier: eTag})
}
- orderToUpdate := allowanceFromTOOPayload(appCtx, *order, payload)
+ orderToUpdate, err := allowanceFromTOOPayload(appCtx, *order, payload)
+ if err != nil {
+ return &models.Order{}, uuid.Nil, err
+ }
return f.updateOrder(appCtx, orderToUpdate)
}
@@ -104,7 +114,10 @@ func (f *orderUpdater) UpdateAllowanceAsCounselor(appCtx appcontext.AppContext,
return &models.Order{}, uuid.Nil, apperror.NewPreconditionFailedError(orderID, query.StaleIdentifierError{StaleIdentifier: eTag})
}
- orderToUpdate := allowanceFromCounselingPayload(appCtx, *order, payload)
+ orderToUpdate, err := allowanceFromCounselingPayload(appCtx, *order, payload)
+ if err != nil {
+ return &models.Order{}, uuid.Nil, err
+ }
return f.updateOrder(appCtx, orderToUpdate)
}
@@ -177,8 +190,9 @@ func (f *orderUpdater) findOrderWithAmendedOrders(appCtx appcontext.AppContext,
return &order, nil
}
-func orderFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.UpdateOrderPayload) models.Order {
+func orderFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.UpdateOrderPayload) (models.Order, error) {
order := existingOrder
+ waf := entitlements.NewWeightAllotmentFetcher()
// update order origin duty location
if payload.OriginDutyLocationID != nil {
@@ -257,7 +271,10 @@ func orderFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.Orde
if payload.Grade != nil {
order.Grade = (*internalmessages.OrderPayGrade)(payload.Grade)
// Calculate new DBWeightAuthorized based on the new grade
- weightAllotment := models.GetWeightAllotment(*order.Grade, order.OrdersType)
+ weightAllotment, err := waf.GetWeightAllotment(appCtx, string(*order.Grade), order.OrdersType)
+ if err != nil {
+ return models.Order{}, err
+ }
weight := weightAllotment.TotalWeightSelf
// Payload does not have this information, retrieve dependents from the existing order
if existingOrder.HasDependents && *order.Entitlement.DependentsAuthorized {
@@ -267,7 +284,7 @@ func orderFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.Orde
order.Entitlement.DBAuthorizedWeight = &weight
}
- return order
+ return order, nil
}
func (f *orderUpdater) amendedOrder(appCtx appcontext.AppContext, userID uuid.UUID, order models.Order, file io.ReadCloser, filename string, storer storage.FileStorer, uploadType models.UploadType) (models.UserUpload, string, *validate.Errors, error) {
@@ -317,8 +334,9 @@ func (f *orderUpdater) amendedOrder(appCtx appcontext.AppContext, userID uuid.UU
return *userUpload, url, nil, nil
}
-func orderFromCounselingPayload(existingOrder models.Order, payload ghcmessages.CounselingUpdateOrderPayload) models.Order {
+func orderFromCounselingPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.CounselingUpdateOrderPayload) (models.Order, error) {
order := existingOrder
+ waf := entitlements.NewWeightAllotmentFetcher()
// update order origin duty location
if payload.OriginDutyLocationID != nil {
@@ -390,7 +408,10 @@ func orderFromCounselingPayload(existingOrder models.Order, payload ghcmessages.
if payload.Grade != nil {
order.Grade = (*internalmessages.OrderPayGrade)(payload.Grade)
// Calculate new DBWeightAuthorized based on the new grade
- weightAllotment := models.GetWeightAllotment(*order.Grade, order.OrdersType)
+ weightAllotment, err := waf.GetWeightAllotment(appCtx, string(*order.Grade), order.OrdersType)
+ if err != nil {
+ return models.Order{}, err
+ }
weight := weightAllotment.TotalWeightSelf
// Payload does not have this information, retrieve dependents from the existing order
if existingOrder.HasDependents && *order.Entitlement.DependentsAuthorized {
@@ -404,11 +425,12 @@ func orderFromCounselingPayload(existingOrder models.Order, payload ghcmessages.
order.HasDependents = *payload.HasDependents
}
- return order
+ return order, nil
}
-func allowanceFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.UpdateAllowancePayload) models.Order {
+func allowanceFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.UpdateAllowancePayload) (models.Order, error) {
order := existingOrder
+ waf := entitlements.NewWeightAllotmentFetcher()
if payload.ProGearWeight != nil {
order.Entitlement.ProGearWeight = int(*payload.ProGearWeight)
@@ -434,7 +456,10 @@ func allowanceFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.
}
// Calculate new DBWeightAuthorized based on the new grade
- weightAllotment := models.GetWeightAllotment(*order.Grade, order.OrdersType)
+ weightAllotment, err := waf.GetWeightAllotment(appCtx, string(*order.Grade), order.OrdersType)
+ if err != nil {
+ return models.Order{}, err
+ }
weight := weightAllotment.TotalWeightSelf
// Payload does not have this information, retrieve dependents from the existing order
if existingOrder.HasDependents && *payload.DependentsAuthorized {
@@ -500,15 +525,16 @@ func allowanceFromTOOPayload(appCtx appcontext.AppContext, existingOrder models.
if order.Entitlement != nil {
unaccompaniedBaggageAllowance, err := models.GetUBWeightAllowance(appCtx, order.OriginDutyLocation.Address.IsOconus, order.NewDutyLocation.Address.IsOconus, order.ServiceMember.Affiliation, order.Grade, &order.OrdersType, &hasDepedents, order.Entitlement.AccompaniedTour, order.Entitlement.DependentsUnderTwelve, order.Entitlement.DependentsTwelveAndOver)
if err == nil {
- weightAllotment.UnaccompaniedBaggageAllowance = unaccompaniedBaggageAllowance
+ order.Entitlement.UBAllowance = &unaccompaniedBaggageAllowance
}
}
- return order
+ return order, nil
}
-func allowanceFromCounselingPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.CounselingUpdateAllowancePayload) models.Order {
+func allowanceFromCounselingPayload(appCtx appcontext.AppContext, existingOrder models.Order, payload ghcmessages.CounselingUpdateAllowancePayload) (models.Order, error) {
order := existingOrder
+ waf := entitlements.NewWeightAllotmentFetcher()
if payload.ProGearWeight != nil {
order.Entitlement.ProGearWeight = int(*payload.ProGearWeight)
@@ -534,7 +560,10 @@ func allowanceFromCounselingPayload(appCtx appcontext.AppContext, existingOrder
}
// Calculate new DBWeightAuthorized based on the new grade
- weightAllotment := models.GetWeightAllotment(*order.Grade, order.OrdersType)
+ weightAllotment, err := waf.GetWeightAllotment(appCtx, string(*order.Grade), order.OrdersType)
+ if err != nil {
+ return models.Order{}, err
+ }
weight := weightAllotment.TotalWeightSelf
// Payload does not have this information, retrieve dependents from the existing order
if existingOrder.HasDependents && *payload.DependentsAuthorized {
@@ -584,21 +613,23 @@ func allowanceFromCounselingPayload(appCtx appcontext.AppContext, existingOrder
if order.NewDutyLocationID != uuid.Nil {
var newDutyLocation models.DutyLocation
newDutyLocation, err := models.FetchDutyLocation(appCtx.DB(), order.NewDutyLocationID)
- if err == nil {
- order.NewDutyLocationID = newDutyLocation.ID
- order.NewDutyLocation = newDutyLocation
+ if err != nil {
+ return models.Order{}, err
}
+ order.NewDutyLocationID = newDutyLocation.ID
+ order.NewDutyLocation = newDutyLocation
}
// Recalculate UB allowance of order entitlement
if order.Entitlement != nil {
unaccompaniedBaggageAllowance, err := models.GetUBWeightAllowance(appCtx, order.OriginDutyLocation.Address.IsOconus, order.NewDutyLocation.Address.IsOconus, order.ServiceMember.Affiliation, order.Grade, &order.OrdersType, payload.DependentsAuthorized, order.Entitlement.AccompaniedTour, order.Entitlement.DependentsUnderTwelve, order.Entitlement.DependentsTwelveAndOver)
- if err == nil {
- weightAllotment.UnaccompaniedBaggageAllowance = unaccompaniedBaggageAllowance
+ if err != nil {
+ return models.Order{}, err
}
+ order.Entitlement.UBAllowance = &unaccompaniedBaggageAllowance
}
- return order
+ return order, nil
}
func (f *orderUpdater) saveDocumentForAmendedOrder(appCtx appcontext.AppContext, doc *models.Document) (*models.Document, error) {
diff --git a/pkg/services/pptas_report/pptas_report_list_fetcher.go b/pkg/services/pptas_report/pptas_report_list_fetcher.go
index b0ce2d24015..95e0f5bb9d0 100644
--- a/pkg/services/pptas_report/pptas_report_list_fetcher.go
+++ b/pkg/services/pptas_report/pptas_report_list_fetcher.go
@@ -19,14 +19,16 @@ type pptasReportListFetcher struct {
moveFetcher services.MoveFetcher
tacFetcher services.TransportationAccountingCodeFetcher
loaFetcher services.LineOfAccountingFetcher
+ waf services.WeightAllotmentFetcher
}
-func NewPPTASReportListFetcher(estimator services.PPMEstimator, moveFetcher services.MoveFetcher, tacFetcher services.TransportationAccountingCodeFetcher, loaFetcher services.LineOfAccountingFetcher) services.PPTASReportListFetcher {
+func NewPPTASReportListFetcher(estimator services.PPMEstimator, moveFetcher services.MoveFetcher, tacFetcher services.TransportationAccountingCodeFetcher, loaFetcher services.LineOfAccountingFetcher, weightAllotmentFetcher services.WeightAllotmentFetcher) services.PPTASReportListFetcher {
return &pptasReportListFetcher{
estimator: estimator,
moveFetcher: moveFetcher,
tacFetcher: tacFetcher,
loaFetcher: loaFetcher,
+ waf: weightAllotmentFetcher,
}
}
@@ -91,7 +93,11 @@ func (f *pptasReportListFetcher) BuildPPTASReportsFromMoves(appCtx appcontext.Ap
report.Address = orders.ServiceMember.ResidentialAddress
if orders.Grade != nil && orders.Entitlement != nil {
- orders.Entitlement.SetWeightAllotment(string(*orders.Grade), orders.OrdersType)
+ entitlement, err := f.waf.GetWeightAllotment(appCtx, string(*orders.Grade), orders.OrdersType)
+ if err != nil {
+ return nil, err
+ }
+ orders.Entitlement.WeightAllotted = &entitlement
}
weightAllotment := orders.Entitlement.WeightAllotment()
diff --git a/pkg/services/pptas_report/pptas_report_list_fetcher_test.go b/pkg/services/pptas_report/pptas_report_list_fetcher_test.go
index 49748c7bc0d..e5d441ea483 100644
--- a/pkg/services/pptas_report/pptas_report_list_fetcher_test.go
+++ b/pkg/services/pptas_report/pptas_report_list_fetcher_test.go
@@ -8,6 +8,7 @@ import (
"github.com/transcom/mymove/pkg/factory"
"github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/models"
+ "github.com/transcom/mymove/pkg/services/entitlements"
mocks "github.com/transcom/mymove/pkg/services/mocks"
)
@@ -16,8 +17,9 @@ func (suite *ReportServiceSuite) TestReportFetcher() {
moveFetcher := mocks.MoveFetcher{}
tacFetcher := mocks.TransportationAccountingCodeFetcher{}
loaFetcher := mocks.LineOfAccountingFetcher{}
+ waf := entitlements.NewWeightAllotmentFetcher()
- reportListFetcher := NewPPTASReportListFetcher(&ppmEstimator, &moveFetcher, &tacFetcher, &loaFetcher)
+ reportListFetcher := NewPPTASReportListFetcher(&ppmEstimator, &moveFetcher, &tacFetcher, &loaFetcher, waf)
// defaultSearchParams := services.MoveTaskOrderFetcherParams{}
appCtx := suite.AppContextForTest()
diff --git a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go
index a0d4ab3a421..9c132a0e830 100644
--- a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go
+++ b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet.go
@@ -24,6 +24,7 @@ import (
"github.com/transcom/mymove/pkg/paperwork"
"github.com/transcom/mymove/pkg/route"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/unit"
)
@@ -194,17 +195,22 @@ func (wa *SSWMaxWeightEntitlement) addLineItem(field string, value int) {
// SSWGetEntitlement calculates the entitlement for the shipment summary worksheet based on the parameters of
// a move (hasDependents, spouseHasProGear)
-func SSWGetEntitlement(grade internalmessages.OrderPayGrade, hasDependents bool, spouseHasProGear bool, ordersType internalmessages.OrdersType) models.SSWMaxWeightEntitlement {
+func SSWGetEntitlement(appCtx appcontext.AppContext, grade internalmessages.OrderPayGrade, hasDependents bool, spouseHasProGear bool, ordersType internalmessages.OrdersType) (models.SSWMaxWeightEntitlement, error) {
sswEntitlements := SSWMaxWeightEntitlement{}
- entitlements := models.GetWeightAllotment(grade, ordersType)
+ waf := entitlements.NewWeightAllotmentFetcher()
+ entitlements, err := waf.GetWeightAllotment(appCtx, string(grade), ordersType)
+ if err != nil {
+ return models.SSWMaxWeightEntitlement{}, nil
+ }
+ //entitlements := models.GetWeightAllotment(grade, ordersType)
sswEntitlements.addLineItem("ProGear", entitlements.ProGearWeight)
sswEntitlements.addLineItem("SpouseProGear", entitlements.ProGearWeightSpouse)
if !hasDependents {
sswEntitlements.addLineItem("Entitlement", entitlements.TotalWeightSelf)
- return models.SSWMaxWeightEntitlement(sswEntitlements)
+ return models.SSWMaxWeightEntitlement(sswEntitlements), nil
}
sswEntitlements.addLineItem("Entitlement", entitlements.TotalWeightSelfPlusDependents)
- return models.SSWMaxWeightEntitlement(sswEntitlements)
+ return models.SSWMaxWeightEntitlement(sswEntitlements), nil
}
// Calculates cost for the Remaining PPM Incentive (pre-tax) field on page 2 of SSW form.
@@ -1074,7 +1080,10 @@ func (SSWPPMComputer *SSWPPMComputer) FetchDataShipmentSummaryWorksheetFormData(
return nil, errors.New("order for requested shipment summary worksheet data does not have a pay grade attached")
}
- weightAllotment := SSWGetEntitlement(*ppmShipment.Shipment.MoveTaskOrder.Orders.Grade, ppmShipment.Shipment.MoveTaskOrder.Orders.HasDependents, ppmShipment.Shipment.MoveTaskOrder.Orders.SpouseHasProGear, ppmShipment.Shipment.MoveTaskOrder.Orders.OrdersType)
+ weightAllotment, err := SSWGetEntitlement(appCtx, *ppmShipment.Shipment.MoveTaskOrder.Orders.Grade, ppmShipment.Shipment.MoveTaskOrder.Orders.HasDependents, ppmShipment.Shipment.MoveTaskOrder.Orders.SpouseHasProGear, ppmShipment.Shipment.MoveTaskOrder.Orders.OrdersType)
+ if err != nil {
+ return nil, err
+ }
maxSit, err := CalculateShipmentSITAllowance(appCtx, ppmShipment.Shipment)
if err != nil {
diff --git a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go
index 8f89327f6f2..e5ff72a4aa7 100644
--- a/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go
+++ b/pkg/services/shipment_summary_worksheet/shipment_summary_worksheet_test.go
@@ -20,6 +20,7 @@ import (
"github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/models"
paperworkgenerator "github.com/transcom/mymove/pkg/paperwork"
+ "github.com/transcom/mymove/pkg/services/entitlements"
"github.com/transcom/mymove/pkg/services/mocks"
storageTest "github.com/transcom/mymove/pkg/storage/test"
"github.com/transcom/mymove/pkg/unit"
@@ -27,9 +28,9 @@ import (
)
func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryWorksheet() {
- //advanceID, _ := uuid.NewV4()
ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
yuma := factory.FetchOrBuildCurrentDutyLocation(suite.DB())
+ waf := entitlements.NewWeightAllotmentFetcher()
fortGordon := factory.FetchOrBuildOrdersDutyLocation(suite.DB())
grade := models.ServiceMemberGradeE9
mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{}
@@ -91,12 +92,14 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW
suite.Equal(yuma.Address.ID, ssd.CurrentDutyLocation.Address.ID)
suite.Equal(fortGordon.ID, ssd.NewDutyLocation.ID)
suite.Equal(fortGordon.Address.ID, ssd.NewDutyLocation.Address.ID)
- gradeWtgAllotment := models.GetWeightAllotment(grade, ordersType)
+ gradeWtgAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(grade), ordersType)
+ suite.NoError(err)
suite.Equal(unit.Pound(gradeWtgAllotment.TotalWeightSelf), ssd.WeightAllotment.Entitlement)
suite.Equal(unit.Pound(gradeWtgAllotment.ProGearWeight), ssd.WeightAllotment.ProGear)
suite.Equal(unit.Pound(500), ssd.WeightAllotment.SpouseProGear)
suite.Require().NotNil(ssd.Order.Grade)
- weightAllotment := models.GetWeightAllotment(*ssd.Order.Grade, ssd.Order.OrdersType)
+ weightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*ssd.Order.Grade), ssd.Order.OrdersType)
+ suite.NoError(err)
// E_9 rank, no dependents, with spouse pro-gear
totalWeight := weightAllotment.TotalWeightSelf + weightAllotment.ProGearWeight + weightAllotment.ProGearWeightSpouse
suite.Require().Nil(err)
@@ -219,6 +222,7 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW
yuma := factory.FetchOrBuildCurrentDutyLocation(suite.DB())
fortGordon := factory.FetchOrBuildOrdersDutyLocation(suite.DB())
grade := models.ServiceMemberGradeE9
+ waf := entitlements.NewWeightAllotmentFetcher()
mockPPMCloseoutFetcher := &mocks.PPMCloseoutFetcher{}
SSWPPMComputer := NewSSWPPMComputer(mockPPMCloseoutFetcher)
@@ -263,12 +267,14 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFetchDataShipmentSummaryW
suite.Equal(yuma.Address.ID, ssd.CurrentDutyLocation.Address.ID)
suite.Equal(fortGordon.ID, ssd.NewDutyLocation.ID)
suite.Equal(fortGordon.Address.ID, ssd.NewDutyLocation.Address.ID)
- gradeWtgAllotment := models.GetWeightAllotment(grade, ordersType)
+ gradeWtgAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(grade), ordersType)
+ suite.NoError(err)
suite.Equal(unit.Pound(gradeWtgAllotment.TotalWeightSelf), ssd.WeightAllotment.Entitlement)
suite.Equal(unit.Pound(gradeWtgAllotment.ProGearWeight), ssd.WeightAllotment.ProGear)
suite.Equal(unit.Pound(500), ssd.WeightAllotment.SpouseProGear)
suite.Require().NotNil(ssd.Order.Grade)
- weightAllotment := models.GetWeightAllotment(*ssd.Order.Grade, ssd.Order.OrdersType)
+ weightAllotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(*ssd.Order.Grade), ssd.Order.OrdersType)
+ suite.NoError(err)
// E_9 rank, no dependents, with spouse pro-gear
totalWeight := weightAllotment.TotalWeightSelf + weightAllotment.ProGearWeight + weightAllotment.ProGearWeightSpouse
suite.Equal(unit.Pound(totalWeight), ssd.WeightAllotment.TotalWeight)
@@ -885,10 +891,12 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatSSWGetEntitlement()
spouseHasProGear := true
hasDependants := true
ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- allotment := models.GetWeightAllotment(models.ServiceMemberGradeE1, ordersType)
+ waf := entitlements.NewWeightAllotmentFetcher()
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE1), ordersType)
+ suite.NoError(err)
expectedTotalWeight := allotment.TotalWeightSelfPlusDependents + allotment.ProGearWeight + allotment.ProGearWeightSpouse
- sswEntitlement := SSWGetEntitlement(models.ServiceMemberGradeE1, hasDependants, spouseHasProGear, ordersType)
-
+ sswEntitlement, err := SSWGetEntitlement(suite.AppContextForTest(), models.ServiceMemberGradeE1, hasDependants, spouseHasProGear, ordersType)
+ suite.NoError(err)
suite.Equal(unit.Pound(expectedTotalWeight), sswEntitlement.TotalWeight)
suite.Equal(unit.Pound(allotment.TotalWeightSelfPlusDependents), sswEntitlement.Entitlement)
suite.Equal(unit.Pound(allotment.ProGearWeightSpouse), sswEntitlement.SpouseProGear)
@@ -898,10 +906,13 @@ func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatSSWGetEntitlement()
func (suite *ShipmentSummaryWorksheetServiceSuite) TestFormatSSWGetEntitlementNoDependants() {
spouseHasProGear := false
hasDependants := false
+ waf := entitlements.NewWeightAllotmentFetcher()
ordersType := internalmessages.OrdersTypePERMANENTCHANGEOFSTATION
- allotment := models.GetWeightAllotment(models.ServiceMemberGradeE1, ordersType)
+ allotment, err := waf.GetWeightAllotment(suite.AppContextForTest(), string(models.ServiceMemberGradeE1), ordersType)
+ suite.NoError(err)
expectedTotalWeight := allotment.TotalWeightSelf + allotment.ProGearWeight + allotment.ProGearWeightSpouse
- sswEntitlement := SSWGetEntitlement(models.ServiceMemberGradeE1, hasDependants, spouseHasProGear, ordersType)
+ sswEntitlement, err := SSWGetEntitlement(suite.AppContextForTest(), models.ServiceMemberGradeE1, hasDependants, spouseHasProGear, ordersType)
+ suite.NoError(err)
suite.Equal(unit.Pound(expectedTotalWeight), sswEntitlement.TotalWeight)
suite.Equal(unit.Pound(allotment.TotalWeightSelf), sswEntitlement.Entitlement)
diff --git a/pkg/services/sit_extension/sit_extension_creator_test.go b/pkg/services/sit_extension/sit_extension_creator_test.go
index 9a3a15afc98..04c53f04d87 100644
--- a/pkg/services/sit_extension/sit_extension_creator_test.go
+++ b/pkg/services/sit_extension/sit_extension_creator_test.go
@@ -7,6 +7,7 @@ import (
"github.com/transcom/mymove/pkg/factory"
"github.com/transcom/mymove/pkg/models"
"github.com/transcom/mymove/pkg/services"
+ "github.com/transcom/mymove/pkg/services/entitlements"
moverouter "github.com/transcom/mymove/pkg/services/move"
movefetcher "github.com/transcom/mymove/pkg/services/move_task_order"
)
@@ -16,7 +17,8 @@ func (suite *SitExtensionServiceSuite) TestSITExtensionCreator() {
// Create move router for SitExtension Createor
moveRouter := moverouter.NewMoveRouter()
sitExtensionCreator := NewSitExtensionCreator(moveRouter)
- movefetcher := movefetcher.NewMoveTaskOrderFetcher()
+ waf := entitlements.NewWeightAllotmentFetcher()
+ movefetcher := movefetcher.NewMoveTaskOrderFetcher(waf)
suite.Run("Success - CreateSITExtension with no status passed in", func() {
// Under test: CreateSITExtension
diff --git a/pkg/testdatagen/make_entitlement.go b/pkg/testdatagen/make_entitlement.go
index e71bf02cec1..442cf8f94b6 100644
--- a/pkg/testdatagen/make_entitlement.go
+++ b/pkg/testdatagen/make_entitlement.go
@@ -3,6 +3,7 @@ package testdatagen
import (
"github.com/gobuffalo/pop/v6"
+ "github.com/transcom/mymove/pkg/gen/internalmessages"
"github.com/transcom/mymove/pkg/models"
)
@@ -14,7 +15,6 @@ func makeEntitlement(db *pop.Connection, assertions Assertions) models.Entitleme
rmeWeight := 1000
ocie := true
grade := assertions.Order.Grade
- ordersType := assertions.Order.OrdersType
proGearWeight := 2000
proGearWeightSpouse := 500
@@ -33,9 +33,46 @@ func makeEntitlement(db *pop.Connection, assertions Assertions) models.Entitleme
RequiredMedicalEquipmentWeight: rmeWeight,
OrganizationalClothingAndIndividualEquipment: ocie,
}
- entitlement.SetWeightAllotment(string(*grade), ordersType)
- dBAuthorizedWeight := entitlement.AuthorizedWeight()
- entitlement.DBAuthorizedWeight = dBAuthorizedWeight
+
+ var hhgAllowance models.HHGAllowance
+ if assertions.Order.OrdersType == internalmessages.OrdersTypeSTUDENTTRAVEL {
+ // Set to student travel allotment
+ entitlement.WeightAllotted = &models.WeightAllotment{
+ TotalWeightSelf: 350,
+ TotalWeightSelfPlusDependents: 350,
+ ProGearWeight: 0,
+ ProGearWeightSpouse: 0,
+ UnaccompaniedBaggageAllowance: 100,
+ }
+ }
+ err := db.RawQuery(`
+ SELECT hhg_allowances.*
+ FROM hhg_allowances
+ INNER JOIN pay_grades ON hhg_allowances.pay_grade_id = pay_grades.id
+ WHERE pay_grades.grade = $1
+ LIMIT 1
+ `, grade).First(&hhgAllowance)
+ if err != nil {
+ // Resort to defaults, for some reason it must've been truncated
+ weightData := getDefaultWeightData(string(*grade))
+ allotment := models.WeightAllotment{
+ TotalWeightSelf: weightData.TotalWeightSelf,
+ TotalWeightSelfPlusDependents: weightData.TotalWeightSelfPlusDependents,
+ ProGearWeight: weightData.ProGearWeight,
+ ProGearWeightSpouse: weightData.ProGearWeightSpouse,
+ }
+ entitlement.WeightAllotted = &allotment
+ dBAuthorizedWeight := entitlement.AuthorizedWeight()
+ entitlement.DBAuthorizedWeight = dBAuthorizedWeight
+ } else {
+ // The db data was found
+ entitlement.WeightAllotted = &models.WeightAllotment{
+ TotalWeightSelf: hhgAllowance.TotalWeightSelf,
+ TotalWeightSelfPlusDependents: hhgAllowance.TotalWeightSelfPlusDependents,
+ ProGearWeight: hhgAllowance.ProGearWeight,
+ ProGearWeightSpouse: hhgAllowance.ProGearWeightSpouse,
+ }
+ }
// Overwrite values with those from assertions
mergeModels(&entitlement, assertions.Entitlement)
@@ -45,6 +82,59 @@ func makeEntitlement(db *pop.Connection, assertions Assertions) models.Entitleme
return entitlement
}
+// Helper function to retrieve default weight data by grade
+func getDefaultWeightData(grade string) struct {
+ TotalWeightSelf int
+ TotalWeightSelfPlusDependents int
+ ProGearWeight int
+ ProGearWeightSpouse int
+} {
+ if data, ok := knownAllowances[grade]; ok {
+ return data
+ }
+ return knownAllowances["EMPTY"] // Default to EMPTY if grade not found. This is just dummy default data
+}
+
+// Default allowances CAO December 2024
+// Note that the testdatagen package has its own default allowance
+var knownAllowances = map[string]struct {
+ TotalWeightSelf int
+ TotalWeightSelfPlusDependents int
+ ProGearWeight int
+ ProGearWeightSpouse int
+}{
+ "EMPTY": {0, 0, 0, 0},
+ "ACADEMY_CADET": {350, 350, 0, 0},
+ "MIDSHIPMAN": {350, 350, 0, 0},
+ "AVIATION_CADET": {7000, 8000, 2000, 500},
+ "E-1": {5000, 8000, 2000, 500},
+ "E-2": {5000, 8000, 2000, 500},
+ "E-3": {5000, 8000, 2000, 500},
+ "E-4": {7000, 8000, 2000, 500},
+ "E-5": {7000, 9000, 2000, 500},
+ "E-6": {8000, 11000, 2000, 500},
+ "E-7": {11000, 13000, 2000, 500},
+ "E-8": {12000, 14000, 2000, 500},
+ "E-9": {13000, 15000, 2000, 500},
+ "E-9SPECIALSENIORENLISTED": {14000, 17000, 2000, 500},
+ "O-1ACADEMYGRADUATE": {10000, 12000, 2000, 500},
+ "O-2": {12500, 13500, 2000, 500},
+ "O-3": {13000, 14500, 2000, 500},
+ "O-4": {14000, 17000, 2000, 500},
+ "O-5": {16000, 17500, 2000, 500},
+ "O-6": {18000, 18000, 2000, 500},
+ "O-7": {18000, 18000, 2000, 500},
+ "O-8": {18000, 18000, 2000, 500},
+ "O-9": {18000, 18000, 2000, 500},
+ "O-10": {18000, 18000, 2000, 500},
+ "W-1": {10000, 12000, 2000, 500},
+ "W-2": {12500, 13500, 2000, 500},
+ "W-3": {13000, 14500, 2000, 500},
+ "W-4": {14000, 17000, 2000, 500},
+ "W-5": {16000, 17500, 2000, 500},
+ "CIVILIAN_EMPLOYEE": {18000, 18000, 2000, 500},
+}
+
func setDependentsAuthorized(assertionDependentsAuthorized *bool) *bool {
dependentsAuthorized := models.BoolPointer(true)
if assertionDependentsAuthorized != nil {
diff --git a/playwright/tests/my/milmove/ppms/entireShipmentCloseout.spec.js b/playwright/tests/my/milmove/ppms/entireShipmentCloseout.spec.js
index 2ab93a21207..6d593a1bfaa 100644
--- a/playwright/tests/my/milmove/ppms/entireShipmentCloseout.spec.js
+++ b/playwright/tests/my/milmove/ppms/entireShipmentCloseout.spec.js
@@ -11,8 +11,11 @@ const multiMoveEnabled = process.env.FEATURE_FLAG_MULTI_MOVE;
test.describe('Entire PPM closeout flow', () => {
test.skip(multiMoveEnabled === 'true', 'Skip if MultiMove workflow is enabled.');
+
forEachViewport(async () => {
test(`flows through happy path for existing shipment`, async ({ customerPpmPage }) => {
+ test.slow();
+ test.setTimeout(300000); // This one has been a headache forever. Shoehorn fix to go way above default "slow" timeout
const move = await customerPpmPage.testHarness.buildApprovedMoveWithPPM();
await customerPpmPage.signInForPPMWithMove(move);
@@ -32,6 +35,8 @@ test.describe('Entire PPM closeout flow', () => {
});
test(`happy path with edits and backs`, async ({ customerPpmPage }) => {
+ test.slow();
+ test.setTimeout(300000); // This one has been a headache forever. Shoehorn fix to go way above default "slow" timeout
const move = await customerPpmPage.testHarness.buildMoveWithPPMShipmentReadyForFinalCloseout();
await customerPpmPage.signInForPPMWithMove(move);
@@ -54,6 +59,7 @@ test.describe('Entire PPM closeout flow', () => {
});
test(`delete complete and incomplete line items`, async ({ customerPpmPage }) => {
+ test.slow();
const move = await customerPpmPage.testHarness.buildMoveWithPPMShipmentReadyForFinalCloseout();
await customerPpmPage.signInForPPMWithMove(move);
@@ -94,6 +100,7 @@ test.describe('Entire PPM closeout flow', () => {
});
test(`deleting weight tickets updates final incentive`, async ({ customerPpmPage }) => {
+ test.slow();
const move = await customerPpmPage.testHarness.buildMoveWithPPMShipmentReadyForFinalCloseout();
await customerPpmPage.signInForPPMWithMove(move);
@@ -129,6 +136,8 @@ test.describe('(MultiMove) Entire PPM closeout flow (MultiMove Workflow)', () =>
forEachViewport(async () => {
test(`flows through happy path for existing shipment`, async ({ customerPpmPage }) => {
+ test.slow();
+ test.setTimeout(300000); // This one has been a headache forever. Shoehorn fix to go way above default "slow" timeout
const move = await customerPpmPage.testHarness.buildApprovedMoveWithPPM();
await customerPpmPage.signInForPPMWithMove(move);
@@ -149,6 +158,8 @@ test.describe('(MultiMove) Entire PPM closeout flow (MultiMove Workflow)', () =>
});
test(`happy path with edits and backs`, async ({ customerPpmPage }) => {
+ test.slow();
+ test.setTimeout(300000); // This one has been a headache forever. Shoehorn fix to go way above default "slow" timeout
const move = await customerPpmPage.testHarness.buildMoveWithPPMShipmentReadyForFinalCloseout();
await customerPpmPage.signInForPPMWithMove(move);
@@ -175,6 +186,7 @@ test.describe('(MultiMove) Entire PPM closeout flow (MultiMove Workflow)', () =>
});
test(`delete complete and incomplete line items`, async ({ customerPpmPage }) => {
+ test.slow();
const move = await customerPpmPage.testHarness.buildMoveWithPPMShipmentReadyForFinalCloseout();
await customerPpmPage.signInForPPMWithMove(move);
@@ -222,6 +234,7 @@ test.describe('(MultiMove) Entire PPM closeout flow (MultiMove Workflow)', () =>
});
test(`deleting weight tickets updates final incentive`, async ({ customerPpmPage }) => {
+ test.slow();
const move = await customerPpmPage.testHarness.buildMoveWithPPMShipmentReadyForFinalCloseout();
await customerPpmPage.signInForPPMWithMove(move);
diff --git a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js
index 16db36fbc3c..064c7e1d63d 100644
--- a/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js
+++ b/playwright/tests/office/servicescounseling/servicesCounselingFlows.spec.js
@@ -47,6 +47,7 @@ test.describe('Services counselor user', () => {
});
test('is able to click on move and submit after using the move code filter', async ({ page }) => {
+ test.slow();
/**
* Move Details page
*/
@@ -65,6 +66,7 @@ test.describe('Services counselor user', () => {
});
test('is able to flag a move for financial review', async ({ page, scPage }) => {
+ test.slow();
// click to trigger financial review modal
await page.getByText('Flag move for financial review').click();
@@ -98,6 +100,7 @@ test.describe('Services counselor user', () => {
});
test('is able to edit a shipment', async ({ page, scPage }) => {
+ test.slow();
await page.locator('[data-testid="ShipmentContainer"] .usa-button').first().click();
await page.locator('#requestedPickupDate').clear();
await page.locator('#requestedPickupDate').fill('16 Mar 2022');
@@ -125,6 +128,7 @@ test.describe('Services counselor user', () => {
await expect(page.locator('.usa-alert__text')).toContainText('Your changes were saved.');
});
test('is able to view Origin GBLOC', async ({ page }) => {
+ test.slow();
// Check for Origin GBLOC label
await expect(page.getByTestId('originGBLOC')).toHaveText('Origin GBLOC');
await expect(page.getByTestId('infoBlock')).toContainText('KKFA');
@@ -138,6 +142,7 @@ test.describe('Services counselor user', () => {
});
test('is able to view USMC as Origin GBLOC', async ({ page }) => {
+ test.slow();
// Check for Origin GBLOC label
await expect(page.getByTestId('originGBLOC')).toHaveText('Origin GBLOC');
await expect(page.getByTestId('infoBlock')).toContainText('KKFA / USMC');
@@ -151,6 +156,7 @@ test.describe('Services counselor user', () => {
});
test('is able to view orders and amended orders', async ({ page }) => {
+ test.slow();
await page.getByRole('link', { name: 'View and edit orders' }).click();
await page.getByTestId('openMenu').click();
await expect(page.getByTestId('DocViewerMenu').getByTestId('button')).toHaveCount(3);
@@ -170,6 +176,7 @@ test.describe('Services counselor user', () => {
});
test('is able to add and delete orders and amended orders', async ({ page, officePage }) => {
+ test.slow();
await page.getByRole('link', { name: 'View and edit orders' }).click();
// check initial quanity of files
@@ -226,6 +233,7 @@ test.describe('Services counselor user', () => {
});
test('is able to add and delete supporting documents', async ({ page, officePage }) => {
+ test.slow();
test.skip(supportingDocsEnabled === 'false', 'Skip if Supporting Documents is not enabled.');
await page.getByRole('link', { name: 'Supporting Documents' }).click();
await expect(page.getByText('No supporting documents have been uploaded.')).toBeVisible();
@@ -260,6 +268,7 @@ test.describe('Services counselor user', () => {
});
test('is able to add a shipment', async ({ page, scPage }) => {
+ test.slow();
const deliveryDate = new Date().toLocaleDateString('en-US');
await expect(page.locator('[data-testid="ShipmentContainer"] .usa-button')).toHaveCount(2);
@@ -292,6 +301,7 @@ test.describe('Services counselor user', () => {
});
test('is able to see and use the left navigation', async ({ page }) => {
+ test.slow();
await expect(page.locator('a[href*="#shipments"]')).toContainText('Shipments');
await expect(page.locator('a[href*="#orders"]')).toContainText('Orders');
await expect(page.locator('a[href*="#allowances"]')).toContainText('Allowances');
@@ -307,6 +317,7 @@ test.describe('Services counselor user', () => {
});
test('is able to edit a shipment', async ({ page, scPage }) => {
+ test.slow();
await page.locator('[data-testid="ShipmentContainer"] .usa-button').first().click();
await page.locator('#requestedPickupDate').clear();
await page.locator('#requestedPickupDate').fill('16 Mar 2022');
@@ -323,6 +334,8 @@ test.describe('Services counselor user', () => {
await expect(page.getByText(LocationLookup, { exact: true })).toBeVisible();
await page.keyboard.press('Enter');
await page.locator('select[name="destinationType"]').selectOption({ label: 'Home of selection (HOS)' });
+ await page.getByLabel('Requested pickup date').fill('16 Mar 2022');
+
await page.locator('[data-testid="submitForm"]').click();
await scPage.waitForLoading();
@@ -330,6 +343,7 @@ test.describe('Services counselor user', () => {
});
test('is able to update destination type if delivery address is unknown', async ({ page, scPage }) => {
+ test.slow();
await page.locator('[data-testid="ShipmentContainer"] .usa-button').first().click();
await page.locator('#requestedPickupDate').clear();
await page.locator('#requestedPickupDate').fill('16 Mar 2022');
@@ -353,6 +367,7 @@ test.describe('Services counselor user', () => {
});
test('is able to see that the tag next to shipment is updated', async ({ page, scPage }) => {
+ test.slow();
// Verify that there's a tag on the left nav that flags missing information
await expect(page.locator('[data-testid="shipment-missing-info-alert"]')).toContainText('1');
@@ -372,6 +387,7 @@ test.describe('Services counselor user', () => {
});
test('can complete review of PPM shipment documents and view documents after', async ({ page, scPage }) => {
+ test.slow();
const move = await scPage.testHarness.buildApprovedMoveWithPPMAllDocTypesOffice();
await scPage.navigateToCloseoutMove(move.locator);
@@ -427,6 +443,7 @@ test.describe('Services counselor user', () => {
});
test('is able to edit/save actual move start date', async ({ page, scPage }) => {
+ test.slow();
// Navigate to the "Review documents" page
await expect(page.getByRole('button', { name: /Review documents/i })).toBeVisible();
await page.getByRole('button', { name: 'Review documents' }).click();
@@ -443,6 +460,7 @@ test.describe('Services counselor user', () => {
});
test('is able to edit/save pickup address', async ({ page, scPage }) => {
+ test.slow();
// Navigate to the "Review documents" page
await expect(page.getByRole('button', { name: /Review documents/i })).toBeVisible();
await page.getByRole('button', { name: 'Review documents' }).click();
@@ -459,6 +477,7 @@ test.describe('Services counselor user', () => {
});
test('is able to edit/save delivery address', async ({ page, scPage }) => {
+ test.slow();
// Navigate to the "Review documents" page
await expect(page.getByRole('button', { name: /Review documents/i })).toBeVisible();
await page.getByRole('button', { name: 'Review documents' }).click();
@@ -475,6 +494,7 @@ test.describe('Services counselor user', () => {
});
test('is able to edit/save advance received', async ({ page, scPage }) => {
+ test.slow();
// Navigate to the "Review documents" page
await expect(page.getByRole('button', { name: /Review documents/i })).toBeVisible();
await page.getByRole('button', { name: 'Review documents' }).click();
@@ -510,6 +530,7 @@ test.describe('Services counselor user', () => {
let fullPpmMoveLocator = '';
test('counselor can see partial PPM ready for closeout', async ({ page, scPage }) => {
+ test.slow();
const partialPpmMoveCloseout = await scPage.testHarness.buildPartialPPMMoveReadyForCloseout();
partialPpmCloseoutLocator = partialPpmMoveCloseout.locator;
await scPage.searchForCloseoutMove(partialPpmCloseoutLocator);
@@ -517,6 +538,7 @@ test.describe('Services counselor user', () => {
});
test('counselor can see partial PPM ready for counseling', async ({ page, scPage }) => {
+ test.slow();
const partialPpmMoveCounseling = await scPage.testHarness.buildPartialPPMMoveReadyForCounseling();
partialPpmCounselingLocator = partialPpmMoveCounseling.locator;
await scPage.searchForMove(partialPpmCounselingLocator);
@@ -524,6 +546,7 @@ test.describe('Services counselor user', () => {
});
test('counselor can see full PPM ready for closeout', async ({ page, scPage }) => {
+ test.slow();
const fullPpmMove = await scPage.testHarness.buildPPMMoveWithCloseout();
fullPpmMoveLocator = fullPpmMove.locator;
await scPage.searchForCloseoutMove(fullPpmMoveLocator);
@@ -534,6 +557,7 @@ test.describe('Services counselor user', () => {
test.describe('Actual expense reimbursement tests', () => {
test.describe('is able to view/edit actual expense reimbursement for non-civilian moves', () => {
test('view/edit actual expense reimbursement - edit shipments page', async ({ page, scPage }) => {
+ test.slow();
const move = await scPage.testHarness.buildSubmittedMoveWithPPMShipmentForSC();
await scPage.navigateToMove(move.locator);
@@ -564,6 +588,7 @@ test.describe('Services counselor user', () => {
});
test('view/edit actual expense reimbursement - PPM closeout review documents', async ({ page, scPage }) => {
+ test.slow();
const move = await scPage.testHarness.buildApprovedMoveWithPPMProgearWeightTicketOffice();
await scPage.navigateToMoveUsingMoveSearch(move.locator);
@@ -593,6 +618,7 @@ test.describe('Services counselor user', () => {
test.describe('is unable to edit actual expense reimbursement for civilian moves', () => {
test('cannot edit actual expense reimbursement - edit shipments page', async ({ page, scPage }) => {
+ test.slow();
const move = await scPage.testHarness.buildSubmittedMoveWithPPMShipmentForSC();
await scPage.navigateToMove(move.locator);
@@ -613,6 +639,7 @@ test.describe('Services counselor user', () => {
});
test('cannot edit actual expense reimbursement - PPM closeout review documents', async ({ page, scPage }) => {
+ test.slow();
const move = await scPage.testHarness.buildApprovedMoveWithPPMProgearWeightTicketOfficeCivilian();
await scPage.navigateToMoveUsingMoveSearch(move.locator);
@@ -637,6 +664,7 @@ test.describe('Services counselor user', () => {
});
test('is unable to view/edit orders after MTO has been created(sent to prime)', async ({ page }) => {
+ test.slow();
await expect(page.getByTestId('view-edit-orders')).toBeHidden();
await expect(page.getByTestId('edit-allowances')).toBeHidden();
});
diff --git a/playwright/tests/office/servicescounseling/servicesCounselingMovingExpenses.spec.js b/playwright/tests/office/servicescounseling/servicesCounselingMovingExpenses.spec.js
index 4933c3616f2..ea3452e5827 100644
--- a/playwright/tests/office/servicescounseling/servicesCounselingMovingExpenses.spec.js
+++ b/playwright/tests/office/servicescounseling/servicesCounselingMovingExpenses.spec.js
@@ -1,6 +1,7 @@
import { test, expect } from './servicesCounselingTestFixture';
test('A service counselor can approve/reject moving expenses', async ({ page, scPage }) => {
+ test.slow();
// Create a move with TestHarness, and then navigate to the move details page for it
const move = await scPage.testHarness.buildApprovedMoveWithPPMMovingExpenseOffice();
await scPage.navigateToCloseoutMove(move.locator);
@@ -94,6 +95,8 @@ test('A service counselor can approve/reject moving expenses', async ({ page, sc
});
test('Review documents page displays correct value for Total days in SIT', async ({ page, scPage }) => {
+ test.slow();
+ test.setTimeout(300000); // This one has been a headache forever. Shoehorn fix to go way above default "slow" timeout
// Create a move with TestHarness, and then navigate to the move details page for it
const move = await scPage.testHarness.buildApprovedMoveWithPPMMovingExpenseOffice();
await scPage.navigateToCloseoutMove(move.locator);
diff --git a/playwright/tests/office/servicescounseling/servicesCounselingQueueFilters.spec.js b/playwright/tests/office/servicescounseling/servicesCounselingQueueFilters.spec.js
index e4ef042c31d..4bd1e13d97c 100644
--- a/playwright/tests/office/servicescounseling/servicesCounselingQueueFilters.spec.js
+++ b/playwright/tests/office/servicescounseling/servicesCounselingQueueFilters.spec.js
@@ -23,6 +23,7 @@ test.describe('Services counselor user', () => {
});
test('is able to filter partial vs full moves based on ppm type', async ({ page }) => {
+ test.slow();
// closeout tab
// Created a single Partial PPM move, so when we search for
@@ -40,6 +41,7 @@ test.describe('Services counselor user', () => {
});
test('is able to filter moves based on PPM status', async ({ page }) => {
+ test.slow();
// Check for Needs closeout filter
await page.locator('th[data-testid="locator"] > div > input').clear();
await page.locator('th[data-testid="locator"] > div > input').fill(moveWithNeedsCloseoutLocator);
@@ -49,6 +51,7 @@ test.describe('Services counselor user', () => {
});
test('is able to filter moves based on destination duty location', async ({ page }) => {
+ test.slow();
// add filter for move code (PPM closeout that has Fort Gordon as
// its destination duty location)
@@ -80,6 +83,7 @@ test.describe('Services counselor user', () => {
});
test('is able to filter moves based on PPM Closeout initiated', async ({ page }) => {
+ test.slow();
const closeoutDate = new Date().toLocaleDateString('en-US');
// first test with bogus date and no moves are found
@@ -108,6 +112,7 @@ test.describe('Services counselor user', () => {
});
test('is able to filter moves based on PPM Closeout location', async ({ page }) => {
+ test.slow();
await page.locator('th[data-testid="locator"] > div > input').fill(moveLocator);
await page.locator('th[data-testid="locator"] > div > input').blur();
// add another filter for the closeout office column checking
diff --git a/playwright/tests/office/txo/tooFlows.spec.js b/playwright/tests/office/txo/tooFlows.spec.js
index 4fae441f2d3..412076deb28 100644
--- a/playwright/tests/office/txo/tooFlows.spec.js
+++ b/playwright/tests/office/txo/tooFlows.spec.js
@@ -643,6 +643,7 @@ test.describe('TOO user', () => {
});
test('approves a delivery address change request for an HHG shipment', async ({ officePage, page }) => {
+ test.setTimeout(300000); // This one has been a headache forever. Shoehorn fix to go way above default "slow" timeout
const shipmentAddressUpdate = await officePage.testHarness.bulidHHGMoveWithAddressChangeRequest();
await officePage.signInAsNewTOOUser();
tooFlowPage = new TooFlowPage(officePage, shipmentAddressUpdate.Shipment.MoveTaskOrder);
diff --git a/scripts/db-truncate b/scripts/db-truncate
index 13835108703..c92cd5aae82 100755
--- a/scripts/db-truncate
+++ b/scripts/db-truncate
@@ -15,7 +15,7 @@ BEGIN
'ports','port_locations', 're_fsc_multipliers', 'ghc_diesel_fuel_prices',
're_zip3s','zip3_distances', 're_contracts', 're_domestic_service_areas',
're_intl_prices', 're_intl_other_prices', 're_domestic_linehaul_prices',
- 're_domestic_service_area_prices', 're_domestic_other_prices')) LOOP
+ 're_domestic_service_area_prices', 're_domestic_other_prices', 'pay_grades', 'hhg_allowances')) LOOP
EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || ' CASCADE';
END LOOP;
END \$\$;
diff --git a/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx b/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx
index c3cc2f27d8b..7fe7c5bc413 100644
--- a/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx
+++ b/src/components/Office/AddOrdersForm/AddOrdersForm.test.jsx
@@ -453,3 +453,23 @@ describe('AddOrdersForm - With Counseling Office', () => {
expect(nextBtn.getAttribute('disabled')).toBeFalsy();
});
});
+describe('AddOrdersForm - Edge Cases and Additional Scenarios', () => {
+ it('disables orders type when safety move is selected', async () => {
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByLabelText('Orders type')).toBeDisabled();
+ });
+
+ it('disables orders type when bluebark move is selected', async () => {
+ render(
+
+
+ ,
+ );
+ expect(screen.getByLabelText('Orders type')).toBeDisabled();
+ });
+});
diff --git a/src/pages/Office/CustomerOnboarding/CreateCustomerForm.test.jsx b/src/pages/Office/CustomerOnboarding/CreateCustomerForm.test.jsx
index 345fa0d491d..e432f02b6e3 100644
--- a/src/pages/Office/CustomerOnboarding/CreateCustomerForm.test.jsx
+++ b/src/pages/Office/CustomerOnboarding/CreateCustomerForm.test.jsx
@@ -678,6 +678,8 @@ describe('CreateCustomerForm', () => {
const saveBtn = await screen.findByRole('button', { name: 'Save' });
expect(saveBtn).toBeInTheDocument();
+ // check the safety move box
+ await userEvent.type(getByTestId('is-safety-move-no'), bluebarkPayload.is_safety_move);
await userEvent.type(getByTestId('is-bluebark-yes'), bluebarkPayload.is_bluebark);
await userEvent.selectOptions(getByLabelText('Branch of service'), ['ARMY']);
diff --git a/src/scenes/Office/api.js b/src/scenes/Office/api.js
deleted file mode 100644
index e6ab7e50622..00000000000
--- a/src/scenes/Office/api.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { getClient, checkResponse } from 'shared/Swagger/api';
-
-// MOVE QUEUE
-export async function RetrieveMovesForOffice(queueType) {
- const client = await getClient();
- const response = await client.apis.queues.showQueue({
- queueType,
- });
- checkResponse(response, 'failed to retrieve moves due to server error');
- return response.body;
-}
diff --git a/swagger-def/internal.yaml b/swagger-def/internal.yaml
index 0a9486e0c83..4ba05eef9c5 100644
--- a/swagger-def/internal.yaml
+++ b/swagger-def/internal.yaml
@@ -3826,6 +3826,8 @@ paths:
description: List of weights allotted entitlement
schema:
$ref: '#/definitions/IndexEntitlements'
+ '500':
+ description: internal server error
/calendar/available_move_dates:
get:
summary: Returns available dates for the move calendar
diff --git a/swagger/internal.yaml b/swagger/internal.yaml
index 99da9030213..77dd643491f 100644
--- a/swagger/internal.yaml
+++ b/swagger/internal.yaml
@@ -5745,6 +5745,8 @@ paths:
description: List of weights allotted entitlement
schema:
$ref: '#/definitions/IndexEntitlements'
+ '500':
+ description: internal server error
/calendar/available_move_dates:
get:
summary: Returns available dates for the move calendar
diff --git a/yarn.lock b/yarn.lock
index dd46ddf509b..13023153627 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2947,6 +2947,11 @@
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz#6801033be7ff87a6b7cadaf5b337c9f366a3c4b0"
integrity sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==
+"@scarf/scarf@=1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@scarf/scarf/-/scarf-1.4.0.tgz#3bbb984085dbd6d982494538b523be1ce6562972"
+ integrity sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==
+
"@sinclair/typebox@^0.23.3":
version "0.23.5"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d"
@@ -16650,10 +16655,12 @@ swagger-client@^3.18.5:
traverse "~0.6.6"
url "~0.11.0"
-swagger-ui-dist@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.2.0.tgz#175e112b3aea756fdbbbb035d4cffef26ac579d1"
- integrity sha512-rLvJBgualxNZcwKOmTFzy4zF1nHy+3S0pUDDR/ageDRZgi8aITSe7pVYiAy03xGQZtqEifjwEtHQE+eF14gveg==
+swagger-ui-dist@^5.18.2:
+ version "5.18.2"
+ resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz#62013074374d272c04ed3030704b88db5aa8c0b7"
+ integrity sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==
+ dependencies:
+ "@scarf/scarf" "=1.4.0"
swc-loader@^0.2.3:
version "0.2.3"